1.1 --- a/pkg/devices/lib/cpm/src/jz4780.cc Mon Jun 01 15:37:38 2020 +0200
1.2 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Mon Jun 01 15:39:31 2020 +0200
1.3 @@ -114,8 +114,8 @@
1.4
1.5 enum Clock_gate_bits : unsigned
1.6 {
1.7 - Clock_gate_lcd = 28, // LCD (in CLKGR0)
1.8 - Clock_gate_tve = 27, // TVE (in CLKGR0)
1.9 + Clock_gate_lcd1 = 28, // LCD (in CLKGR0)
1.10 + Clock_gate_lcd0 = 27, // TVE (in CLKGR0)
1.11 Clock_gate_hdmi = 9, // HDMI (in CLKGR1)
1.12 Clock_gate_smb4 = 12, // SMB4 (in CLKGR1)
1.13 Clock_gate_smb3 = 0, // SMB3 (in CLKGR1)
1.14 @@ -210,7 +210,7 @@
1.15 {
1.16 uint8_t d = get_field(reg, mask, shift);
1.17
1.18 - // NOTE: Value 14 stops the clock, 15 presumably resumes the clock.
1.19 + // NOTE: Value 15 stops the clock, 14 presumably resumes the clock.
1.20
1.21 return (d < 14) ? d + 1 : 1;
1.22 }
1.23 @@ -239,6 +239,20 @@
1.24 return _regs[pll_reg] & (1 << Pll_bypassed);
1.25 }
1.26
1.27 +void
1.28 +Cpm_jz4780_chip::pll_enable(uint32_t pll_reg)
1.29 +{
1.30 + _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled);
1.31 + while (!(_regs[pll_reg] & (1 << Pll_stable)));
1.32 +}
1.33 +
1.34 +void
1.35 +Cpm_jz4780_chip::pll_disable(uint32_t pll_reg)
1.36 +{
1.37 + _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled);
1.38 + while (_regs[pll_reg] & (1 << Pll_stable));
1.39 +}
1.40 +
1.41 // Feedback (13-bit) multiplier.
1.42
1.43 uint16_t
1.44 @@ -352,12 +366,12 @@
1.45 return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1;
1.46 }
1.47
1.48 -// LCD clock (LPCLK) divider for LCD0 pixel clock.
1.49 +// LCD clock (LPCLK) divider for LCD0 or LCD1 pixel clock.
1.50
1.51 uint8_t
1.52 -Cpm_jz4780_chip::get_lcd_pixel_divider()
1.53 +Cpm_jz4780_chip::get_lcd_pixel_divider(uint8_t controller)
1.54 {
1.55 - return get_field(Lcd_divider0, 0xff, Lcd_divider_value) + 1;
1.56 + return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0xff, Lcd_divider_value) + 1;
1.57 }
1.58
1.59 // Memory clock (DDR_CLK) divider.
1.60 @@ -394,23 +408,25 @@
1.61 // NOTE: This only supports the first LCD peripheral.
1.62
1.63 void
1.64 -Cpm_jz4780_chip::set_lcd_pixel_divider(uint16_t division)
1.65 +Cpm_jz4780_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division)
1.66 {
1.67 + uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0;
1.68 +
1.69 if ((division < 1) || (division > 256))
1.70 return;
1.71
1.72 // Enable change.
1.73
1.74 - _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable;
1.75 + _regs[divider] = _regs[divider] | Lcd_change_enable;
1.76
1.77 // Set the divider.
1.78
1.79 - set_field(Lcd_divider0, 0xff, Lcd_divider_value, division - 1);
1.80 + set_field(divider, 0xff, Lcd_divider_value, division - 1);
1.81
1.82 // Restart clock and disable change.
1.83
1.84 - while (_regs[Lcd_divider0] & Lcd_change_busy);
1.85 - _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~Lcd_change_enable;
1.86 + while (_regs[divider] & Lcd_change_busy);
1.87 + _regs[divider] = _regs[divider] & ~Lcd_change_enable;
1.88 }
1.89
1.90
1.91 @@ -432,13 +448,22 @@
1.92 void
1.93 Cpm_jz4780_chip::start_lcd()
1.94 {
1.95 - _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd);
1.96 + // JZ4780 apparently needs LCD0/TVE to be ungated for the LCD peripheral to
1.97 + // work. The Linux 3.0.8 vendor kernel reveals that the TVE clock is actually
1.98 + // LCD0 and that the LCD clock is actually LCD1.
1.99 +
1.100 + // According to the 3.0.8 kernel, LCD1 is the parent of LCD0. However, LCD0
1.101 + // does seem to operate without LCD1 enabled.
1.102 +
1.103 + _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd1);
1.104 + _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd0);
1.105 }
1.106
1.107 void
1.108 Cpm_jz4780_chip::stop_lcd()
1.109 {
1.110 - _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd);
1.111 + _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd1);
1.112 + _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd0);
1.113 }
1.114
1.115 void
1.116 @@ -609,15 +634,15 @@
1.117 }
1.118
1.119 uint8_t
1.120 -Cpm_jz4780_chip::get_lcd_source()
1.121 +Cpm_jz4780_chip::get_lcd_source(uint8_t controller)
1.122 {
1.123 - return get_field(Lcd_divider0, 0x3, Clock_source_lcd);
1.124 + return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0x3, Clock_source_lcd);
1.125 }
1.126
1.127 uint32_t
1.128 -Cpm_jz4780_chip::get_lcd_source_frequency()
1.129 +Cpm_jz4780_chip::get_lcd_source_frequency(uint8_t controller)
1.130 {
1.131 - switch (get_lcd_source())
1.132 + switch (get_lcd_source(controller))
1.133 {
1.134 case Source_main:
1.135 return get_main_frequency();
1.136 @@ -631,20 +656,22 @@
1.137 }
1.138
1.139 void
1.140 -Cpm_jz4780_chip::set_lcd_source(uint8_t source)
1.141 +Cpm_jz4780_chip::set_lcd_source(uint8_t controller, uint8_t source)
1.142 {
1.143 + uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0;
1.144 +
1.145 // Stop clock and enable change.
1.146
1.147 - _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable | Lcd_clock_stop;
1.148 + _regs[divider] = _regs[divider] | Lcd_change_enable | Lcd_clock_stop;
1.149
1.150 // Set the source.
1.151
1.152 - set_field(Lcd_divider0, 0x03, Clock_source_lcd, source);
1.153 + set_field(divider, 0x03, Clock_source_lcd, source);
1.154
1.155 // Restart clock and disable change.
1.156
1.157 - while (_regs[Lcd_divider0] & Lcd_change_busy);
1.158 - _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~(Lcd_change_enable | Lcd_clock_stop);
1.159 + while (_regs[divider] & Lcd_change_busy);
1.160 + _regs[divider] = _regs[divider] & ~(Lcd_change_enable | Lcd_clock_stop);
1.161 }
1.162
1.163 uint8_t
1.164 @@ -731,12 +758,12 @@
1.165 return get_hdmi_source_frequency() / get_hdmi_divider();
1.166 }
1.167
1.168 -// Clock frequency for the LCD0 controller.
1.169 +// Clock frequency for the LCD0 or LCD1 controller.
1.170
1.171 uint32_t
1.172 -Cpm_jz4780_chip::get_lcd_pixel_frequency()
1.173 +Cpm_jz4780_chip::get_lcd_pixel_frequency(uint8_t controller)
1.174 {
1.175 - return get_lcd_source_frequency() / get_lcd_pixel_divider();
1.176 + return get_lcd_source_frequency(controller) / get_lcd_pixel_divider(controller);
1.177 }
1.178
1.179 // Clock frequency for the memory.
1.180 @@ -779,6 +806,7 @@
1.181 // Switch to the video PLL and attempt to set the divider.
1.182
1.183 set_hdmi_source(Source_pll_V);
1.184 + pll_enable(Pll_control_V);
1.185 set_hdmi_divider(get_hdmi_source_frequency() / pclk);
1.186 }
1.187
1.188 @@ -791,8 +819,11 @@
1.189 {
1.190 // Switch to the video PLL and attempt to set the divider.
1.191
1.192 - set_lcd_source(Source_pll_V);
1.193 - set_lcd_pixel_divider(get_lcd_source_frequency() / pclk);
1.194 + set_lcd_source(0, Source_pll_V);
1.195 + set_lcd_source(1, Source_pll_V);
1.196 + pll_enable(Pll_control_V);
1.197 + set_lcd_pixel_divider(0, get_lcd_source_frequency() / pclk);
1.198 + set_lcd_pixel_divider(1, get_lcd_source_frequency() / pclk);
1.199 }
1.200
1.201 // NOTE: Compatibility method. Probably needs reviewing.