1.1 --- a/pkg/devices/lib/cpm/include/cpm-jz4780.h Mon Jun 01 15:37:38 2020 +0200
1.2 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Mon Jun 01 15:39:31 2020 +0200
1.3 @@ -51,6 +51,8 @@
1.4 int have_pll(uint32_t pll_reg);
1.5 int pll_enabled(uint32_t pll_reg);
1.6 int pll_bypassed(uint32_t pll_reg);
1.7 + void pll_disable(uint32_t pll_reg);
1.8 + void pll_enable(uint32_t pll_reg);
1.9
1.10 // General frequency modifiers.
1.11
1.12 @@ -64,7 +66,7 @@
1.13 // Clock dividers.
1.14
1.15 void set_hdmi_divider(uint16_t division);
1.16 - void set_lcd_pixel_divider(uint16_t division);
1.17 + void set_lcd_pixel_divider(uint8_t controller, uint16_t division);
1.18
1.19 // Clock control.
1.20
1.21 @@ -78,7 +80,7 @@
1.22
1.23 void set_hclock2_source(uint8_t source);
1.24 void set_hdmi_source(uint8_t source);
1.25 - void set_lcd_source(uint8_t source);
1.26 + void set_lcd_source(uint8_t controller, uint8_t source);
1.27
1.28 public:
1.29 void set_pclock_source(uint8_t source);
1.30 @@ -94,7 +96,7 @@
1.31 uint8_t get_hclock2_divider();
1.32 uint8_t get_pclock_divider();
1.33 uint8_t get_hdmi_divider();
1.34 - uint8_t get_lcd_pixel_divider();
1.35 + uint8_t get_lcd_pixel_divider(uint8_t controller = 0);
1.36 uint8_t get_memory_divider();
1.37
1.38 // Clock control.
1.39 @@ -119,7 +121,7 @@
1.40 uint8_t get_hclock0_source();
1.41 uint8_t get_hclock2_source();
1.42 uint8_t get_hdmi_source();
1.43 - uint8_t get_lcd_source();
1.44 + uint8_t get_lcd_source(uint8_t controller = 0);
1.45 uint8_t get_memory_source();
1.46 uint8_t get_pclock_source();
1.47
1.48 @@ -127,7 +129,7 @@
1.49 uint32_t get_hclock0_source_frequency();
1.50 uint32_t get_hclock2_source_frequency();
1.51 uint32_t get_hdmi_source_frequency();
1.52 - uint32_t get_lcd_source_frequency();
1.53 + uint32_t get_lcd_source_frequency(uint8_t controller = 0);
1.54 uint32_t get_memory_source_frequency();
1.55 uint32_t get_pclock_source_frequency();
1.56
1.57 @@ -137,7 +139,7 @@
1.58 uint32_t get_hclock0_frequency();
1.59 uint32_t get_hclock2_frequency();
1.60 uint32_t get_hdmi_frequency();
1.61 - uint32_t get_lcd_pixel_frequency();
1.62 + uint32_t get_lcd_pixel_frequency(uint8_t controller = 0);
1.63 uint32_t get_memory_frequency();
1.64 uint32_t get_pclock_frequency();
1.65
2.1 --- a/pkg/devices/lib/cpm/src/jz4780.cc Mon Jun 01 15:37:38 2020 +0200
2.2 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Mon Jun 01 15:39:31 2020 +0200
2.3 @@ -114,8 +114,8 @@
2.4
2.5 enum Clock_gate_bits : unsigned
2.6 {
2.7 - Clock_gate_lcd = 28, // LCD (in CLKGR0)
2.8 - Clock_gate_tve = 27, // TVE (in CLKGR0)
2.9 + Clock_gate_lcd1 = 28, // LCD (in CLKGR0)
2.10 + Clock_gate_lcd0 = 27, // TVE (in CLKGR0)
2.11 Clock_gate_hdmi = 9, // HDMI (in CLKGR1)
2.12 Clock_gate_smb4 = 12, // SMB4 (in CLKGR1)
2.13 Clock_gate_smb3 = 0, // SMB3 (in CLKGR1)
2.14 @@ -210,7 +210,7 @@
2.15 {
2.16 uint8_t d = get_field(reg, mask, shift);
2.17
2.18 - // NOTE: Value 14 stops the clock, 15 presumably resumes the clock.
2.19 + // NOTE: Value 15 stops the clock, 14 presumably resumes the clock.
2.20
2.21 return (d < 14) ? d + 1 : 1;
2.22 }
2.23 @@ -239,6 +239,20 @@
2.24 return _regs[pll_reg] & (1 << Pll_bypassed);
2.25 }
2.26
2.27 +void
2.28 +Cpm_jz4780_chip::pll_enable(uint32_t pll_reg)
2.29 +{
2.30 + _regs[pll_reg] = _regs[pll_reg] | (1 << Pll_enabled);
2.31 + while (!(_regs[pll_reg] & (1 << Pll_stable)));
2.32 +}
2.33 +
2.34 +void
2.35 +Cpm_jz4780_chip::pll_disable(uint32_t pll_reg)
2.36 +{
2.37 + _regs[pll_reg] = _regs[pll_reg] & ~(1 << Pll_enabled);
2.38 + while (_regs[pll_reg] & (1 << Pll_stable));
2.39 +}
2.40 +
2.41 // Feedback (13-bit) multiplier.
2.42
2.43 uint16_t
2.44 @@ -352,12 +366,12 @@
2.45 return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1;
2.46 }
2.47
2.48 -// LCD clock (LPCLK) divider for LCD0 pixel clock.
2.49 +// LCD clock (LPCLK) divider for LCD0 or LCD1 pixel clock.
2.50
2.51 uint8_t
2.52 -Cpm_jz4780_chip::get_lcd_pixel_divider()
2.53 +Cpm_jz4780_chip::get_lcd_pixel_divider(uint8_t controller)
2.54 {
2.55 - return get_field(Lcd_divider0, 0xff, Lcd_divider_value) + 1;
2.56 + return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0xff, Lcd_divider_value) + 1;
2.57 }
2.58
2.59 // Memory clock (DDR_CLK) divider.
2.60 @@ -394,23 +408,25 @@
2.61 // NOTE: This only supports the first LCD peripheral.
2.62
2.63 void
2.64 -Cpm_jz4780_chip::set_lcd_pixel_divider(uint16_t division)
2.65 +Cpm_jz4780_chip::set_lcd_pixel_divider(uint8_t controller, uint16_t division)
2.66 {
2.67 + uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0;
2.68 +
2.69 if ((division < 1) || (division > 256))
2.70 return;
2.71
2.72 // Enable change.
2.73
2.74 - _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable;
2.75 + _regs[divider] = _regs[divider] | Lcd_change_enable;
2.76
2.77 // Set the divider.
2.78
2.79 - set_field(Lcd_divider0, 0xff, Lcd_divider_value, division - 1);
2.80 + set_field(divider, 0xff, Lcd_divider_value, division - 1);
2.81
2.82 // Restart clock and disable change.
2.83
2.84 - while (_regs[Lcd_divider0] & Lcd_change_busy);
2.85 - _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~Lcd_change_enable;
2.86 + while (_regs[divider] & Lcd_change_busy);
2.87 + _regs[divider] = _regs[divider] & ~Lcd_change_enable;
2.88 }
2.89
2.90
2.91 @@ -432,13 +448,22 @@
2.92 void
2.93 Cpm_jz4780_chip::start_lcd()
2.94 {
2.95 - _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd);
2.96 + // JZ4780 apparently needs LCD0/TVE to be ungated for the LCD peripheral to
2.97 + // work. The Linux 3.0.8 vendor kernel reveals that the TVE clock is actually
2.98 + // LCD0 and that the LCD clock is actually LCD1.
2.99 +
2.100 + // According to the 3.0.8 kernel, LCD1 is the parent of LCD0. However, LCD0
2.101 + // does seem to operate without LCD1 enabled.
2.102 +
2.103 + _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd1);
2.104 + _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd0);
2.105 }
2.106
2.107 void
2.108 Cpm_jz4780_chip::stop_lcd()
2.109 {
2.110 - _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd);
2.111 + _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd1);
2.112 + _regs[Clock_gate0] = _regs[Clock_gate0] | (1 << Clock_gate_lcd0);
2.113 }
2.114
2.115 void
2.116 @@ -609,15 +634,15 @@
2.117 }
2.118
2.119 uint8_t
2.120 -Cpm_jz4780_chip::get_lcd_source()
2.121 +Cpm_jz4780_chip::get_lcd_source(uint8_t controller)
2.122 {
2.123 - return get_field(Lcd_divider0, 0x3, Clock_source_lcd);
2.124 + return get_field(controller ? Lcd_divider1 : Lcd_divider0, 0x3, Clock_source_lcd);
2.125 }
2.126
2.127 uint32_t
2.128 -Cpm_jz4780_chip::get_lcd_source_frequency()
2.129 +Cpm_jz4780_chip::get_lcd_source_frequency(uint8_t controller)
2.130 {
2.131 - switch (get_lcd_source())
2.132 + switch (get_lcd_source(controller))
2.133 {
2.134 case Source_main:
2.135 return get_main_frequency();
2.136 @@ -631,20 +656,22 @@
2.137 }
2.138
2.139 void
2.140 -Cpm_jz4780_chip::set_lcd_source(uint8_t source)
2.141 +Cpm_jz4780_chip::set_lcd_source(uint8_t controller, uint8_t source)
2.142 {
2.143 + uint32_t divider = controller ? Lcd_divider1 : Lcd_divider0;
2.144 +
2.145 // Stop clock and enable change.
2.146
2.147 - _regs[Lcd_divider0] = _regs[Lcd_divider0] | Lcd_change_enable | Lcd_clock_stop;
2.148 + _regs[divider] = _regs[divider] | Lcd_change_enable | Lcd_clock_stop;
2.149
2.150 // Set the source.
2.151
2.152 - set_field(Lcd_divider0, 0x03, Clock_source_lcd, source);
2.153 + set_field(divider, 0x03, Clock_source_lcd, source);
2.154
2.155 // Restart clock and disable change.
2.156
2.157 - while (_regs[Lcd_divider0] & Lcd_change_busy);
2.158 - _regs[Lcd_divider0] = _regs[Lcd_divider0] & ~(Lcd_change_enable | Lcd_clock_stop);
2.159 + while (_regs[divider] & Lcd_change_busy);
2.160 + _regs[divider] = _regs[divider] & ~(Lcd_change_enable | Lcd_clock_stop);
2.161 }
2.162
2.163 uint8_t
2.164 @@ -731,12 +758,12 @@
2.165 return get_hdmi_source_frequency() / get_hdmi_divider();
2.166 }
2.167
2.168 -// Clock frequency for the LCD0 controller.
2.169 +// Clock frequency for the LCD0 or LCD1 controller.
2.170
2.171 uint32_t
2.172 -Cpm_jz4780_chip::get_lcd_pixel_frequency()
2.173 +Cpm_jz4780_chip::get_lcd_pixel_frequency(uint8_t controller)
2.174 {
2.175 - return get_lcd_source_frequency() / get_lcd_pixel_divider();
2.176 + return get_lcd_source_frequency(controller) / get_lcd_pixel_divider(controller);
2.177 }
2.178
2.179 // Clock frequency for the memory.
2.180 @@ -779,6 +806,7 @@
2.181 // Switch to the video PLL and attempt to set the divider.
2.182
2.183 set_hdmi_source(Source_pll_V);
2.184 + pll_enable(Pll_control_V);
2.185 set_hdmi_divider(get_hdmi_source_frequency() / pclk);
2.186 }
2.187
2.188 @@ -791,8 +819,11 @@
2.189 {
2.190 // Switch to the video PLL and attempt to set the divider.
2.191
2.192 - set_lcd_source(Source_pll_V);
2.193 - set_lcd_pixel_divider(get_lcd_source_frequency() / pclk);
2.194 + set_lcd_source(0, Source_pll_V);
2.195 + set_lcd_source(1, Source_pll_V);
2.196 + pll_enable(Pll_control_V);
2.197 + set_lcd_pixel_divider(0, get_lcd_source_frequency() / pclk);
2.198 + set_lcd_pixel_divider(1, get_lcd_source_frequency() / pclk);
2.199 }
2.200
2.201 // NOTE: Compatibility method. Probably needs reviewing.