1.1 --- a/pkg/devices/lib/cpm/src/jz4780.cc Sat Jan 25 16:07:18 2020 +0100
1.2 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Fri May 22 00:17:25 2020 +0200
1.3 @@ -3,7 +3,7 @@
1.4 * provided by the jz4780 and related SoCs. The power management
1.5 * functionality could be exposed using a separate driver.
1.6 *
1.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk>
1.8 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk>
1.9 *
1.10 * This program is free software; you can redistribute it and/or
1.11 * modify it under the terms of the GNU General Public License as
1.12 @@ -48,6 +48,12 @@
1.13 Msc_divider2 = 0x0a8, // MSC2CDR
1.14 Uhc_divider = 0x06c, // UHCCDR
1.15 Ssi_divider = 0x074, // SSICDR
1.16 +
1.17 + // ...
1.18 +
1.19 + Hdmi_divider = 0x08c, // HDMICDR
1.20 +
1.21 + // ...
1.22 };
1.23
1.24 enum Clock_bits : unsigned
1.25 @@ -78,23 +84,39 @@
1.26 Clock_source_ddr = 30, // DCS
1.27 Clock_source_i2s = 31, // I2CS
1.28 Clock_source_lcd = 30, // LPCS
1.29 + Clock_source_hdmi = 30, // HPCS
1.30 };
1.31
1.32 enum Clock_sources : unsigned
1.33 {
1.34 + // Main clock sources.
1.35 +
1.36 Source_pll_A = 1, // APLL
1.37 Source_external = 2, // EXCLK
1.38 Source_realtime = 3, // RTCLK
1.39 - Source_main_frequency = 1, // SCLK_A
1.40 - Source_pll_M = 2, // MPLL
1.41 - Source_pll_E = 3, // EPLL
1.42 - Source_pll_V = 3, // VPLL
1.43 +
1.44 + // Stoppable clock sources.
1.45 +
1.46 + Source_mux_stopped = 0,
1.47 + Source_mux_main = 1, // SCLK_A
1.48 + Source_mux_pll_M = 2, // MPLL
1.49 + Source_mux_pll_E = 3, // EPLL
1.50 + Source_mux_realtime = 3, // RTCLK (TCK)
1.51 +
1.52 + // Unstoppable clock sources.
1.53 +
1.54 + Source_main = 0, // SCLK_A
1.55 + Source_pll_M = 1, // MPLL
1.56 + Source_pll_E = 2, // EPLL
1.57 + Source_pll_V = 2, // VPLL
1.58 + Source_otg_phy = 3, // OTG_PHY
1.59 };
1.60
1.61 enum Clock_gate_bits : unsigned
1.62 {
1.63 Clock_gate_lcd = 28, // LCD (in CLKGR0)
1.64 Clock_gate_tve = 27, // TVE (in CLKGR0)
1.65 + Clock_gate_hdmi = 9, // HDMI (in CLKGR1)
1.66 Clock_gate_smb4 = 12, // SMB4 (in CLKGR1)
1.67 Clock_gate_smb3 = 0, // SMB3 (in CLKGR1)
1.68 Clock_gate_smb2 = 25, // SMB2 (in CLKGR0)
1.69 @@ -114,14 +136,23 @@
1.70 enum Divider_bits : unsigned
1.71 {
1.72 Ddr_divider_value = 0, // DDRCDR
1.73 + Hdmi_divider_value = 0, // HDMICDR
1.74 Lcd_divider_value = 0, // LPCDR
1.75 };
1.76
1.77 -enum Lcd_clock_bits : unsigned
1.78 +enum Lcd_clock_values : unsigned
1.79 {
1.80 - Lcd_change_enable = 0x1000, // CE_LCD
1.81 - Lcd_change_busy = 0x0800, // LCD_BUSY
1.82 - Lcd_clock_stop = 0x0400, // LCD_STOP
1.83 + Lcd_change_enable = 0x10000000, // CE_LCD
1.84 + Lcd_change_busy = 0x08000000, // LCD_BUSY
1.85 + Lcd_clock_stop = 0x04000000, // LCD_STOP
1.86 +};
1.87 +
1.88 +enum Hdmi_divider_values : unsigned
1.89 +{
1.90 + Hdmi_select_mask = 0xc0000000, // HPCS
1.91 + Hdmi_change_enable = 0x20000000, // CE_HDMI
1.92 + Hdmi_change_busy = 0x10000000, // HDMI_BUSY
1.93 + Hdmi_clock_stop = 0x08000000, // HDMI_STOP
1.94 };
1.95
1.96
1.97 @@ -313,6 +344,14 @@
1.98 return _get_divider(Clock_control, 0xf, Clock_pclock_divider);
1.99 }
1.100
1.101 +// HDMI clock divider.
1.102 +
1.103 +uint8_t
1.104 +Cpm_jz4780_chip::get_hdmi_divider()
1.105 +{
1.106 + return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1;
1.107 +}
1.108 +
1.109 // LCD clock (LPCLK) divider for LCD0 pixel clock.
1.110
1.111 uint8_t
1.112 @@ -329,6 +368,28 @@
1.113 return _get_divider(Ddr_divider, 0xf, Ddr_divider_value);
1.114 }
1.115
1.116 +// HDMI clock divider.
1.117 +
1.118 +void
1.119 +Cpm_jz4780_chip::set_hdmi_divider(uint16_t division)
1.120 +{
1.121 + if ((division < 1) || (division > 256))
1.122 + return;
1.123 +
1.124 + // Enable change.
1.125 +
1.126 + _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable;
1.127 +
1.128 + // Set the divider.
1.129 +
1.130 + set_field(Hdmi_divider, 0xff, Hdmi_divider_value, division - 1);
1.131 +
1.132 + // Restart clock and disable change.
1.133 +
1.134 + while (_regs[Hdmi_divider] & Hdmi_change_busy);
1.135 + _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~Hdmi_change_enable;
1.136 +}
1.137 +
1.138 // LCD pixel clock divider.
1.139 // NOTE: This only supports the first LCD peripheral.
1.140
1.141 @@ -357,6 +418,18 @@
1.142 // Clock gating control.
1.143
1.144 void
1.145 +Cpm_jz4780_chip::start_hdmi()
1.146 +{
1.147 + _regs[Clock_gate1] = _regs[Clock_gate1] & ~(1 << Clock_gate_hdmi);
1.148 +}
1.149 +
1.150 +void
1.151 +Cpm_jz4780_chip::stop_hdmi()
1.152 +{
1.153 + _regs[Clock_gate1] = _regs[Clock_gate1] | (1 << Clock_gate_hdmi);
1.154 +}
1.155 +
1.156 +void
1.157 Cpm_jz4780_chip::start_lcd()
1.158 {
1.159 _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd);
1.160 @@ -415,9 +488,9 @@
1.161 {
1.162 switch (get_memory_source())
1.163 {
1.164 - case Source_main_frequency:
1.165 + case Source_mux_main:
1.166 return get_main_frequency();
1.167 - case Source_pll_M:
1.168 + case Source_mux_pll_M:
1.169 return get_pll_frequency(Pll_control_M);
1.170 default:
1.171 return 0;
1.172 @@ -435,11 +508,11 @@
1.173 {
1.174 switch (get_cpu_source())
1.175 {
1.176 - case Source_main_frequency:
1.177 + case Source_mux_main:
1.178 return get_main_frequency();
1.179 - case Source_pll_M:
1.180 + case Source_mux_pll_M:
1.181 return get_pll_frequency(Pll_control_M);
1.182 - case Source_pll_E:
1.183 + case Source_mux_pll_E:
1.184 return get_pll_frequency(Pll_control_E);
1.185 default:
1.186 return 0;
1.187 @@ -457,11 +530,11 @@
1.188 {
1.189 switch (get_hclock0_source())
1.190 {
1.191 - case Source_main_frequency:
1.192 + case Source_mux_main:
1.193 return get_main_frequency();
1.194 - case Source_pll_M:
1.195 + case Source_mux_pll_M:
1.196 return get_pll_frequency(Pll_control_M);
1.197 - case Source_pll_E:
1.198 + case Source_mux_pll_E:
1.199 return get_pll_frequency(Pll_control_E);
1.200 default:
1.201 return 0;
1.202 @@ -479,11 +552,11 @@
1.203 {
1.204 switch (get_hclock2_source())
1.205 {
1.206 - case Source_main_frequency:
1.207 + case Source_mux_main:
1.208 return get_main_frequency();
1.209 - case Source_pll_M:
1.210 + case Source_mux_pll_M:
1.211 return get_pll_frequency(Pll_control_M);
1.212 - case Source_realtime:
1.213 + case Source_mux_realtime:
1.214 return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code
1.215 default:
1.216 return 0;
1.217 @@ -497,6 +570,45 @@
1.218 }
1.219
1.220 uint8_t
1.221 +Cpm_jz4780_chip::get_hdmi_source()
1.222 +{
1.223 + return get_field(Hdmi_divider, 0x3, Clock_source_hdmi);
1.224 +}
1.225 +
1.226 +uint32_t
1.227 +Cpm_jz4780_chip::get_hdmi_source_frequency()
1.228 +{
1.229 + switch (get_hdmi_source())
1.230 + {
1.231 + case Source_main:
1.232 + return get_main_frequency();
1.233 + case Source_pll_M:
1.234 + return get_pll_frequency(Pll_control_M);
1.235 + case Source_pll_V:
1.236 + return get_pll_frequency(Pll_control_V);
1.237 + default:
1.238 + return 0;
1.239 + }
1.240 +}
1.241 +
1.242 +void
1.243 +Cpm_jz4780_chip::set_hdmi_source(uint8_t source)
1.244 +{
1.245 + // Stop clock and enable change.
1.246 +
1.247 + _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable | Hdmi_clock_stop;
1.248 +
1.249 + // Set the source.
1.250 +
1.251 + set_field(Hdmi_divider, 0x03, Clock_source_hdmi, source);
1.252 +
1.253 + // Restart clock and disable change.
1.254 +
1.255 + while (_regs[Hdmi_divider] & Hdmi_change_busy);
1.256 + _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~(Hdmi_change_enable | Hdmi_clock_stop);
1.257 +}
1.258 +
1.259 +uint8_t
1.260 Cpm_jz4780_chip::get_lcd_source()
1.261 {
1.262 return get_field(Lcd_divider0, 0x3, Clock_source_lcd);
1.263 @@ -507,7 +619,7 @@
1.264 {
1.265 switch (get_lcd_source())
1.266 {
1.267 - case Source_main_frequency:
1.268 + case Source_main:
1.269 return get_main_frequency();
1.270 case Source_pll_M:
1.271 return get_pll_frequency(Pll_control_M);
1.272 @@ -611,6 +723,14 @@
1.273 return get_pclock_source_frequency() / get_pclock_divider();
1.274 }
1.275
1.276 +// Clock frequency for the HDMI peripheral.
1.277 +
1.278 +uint32_t
1.279 +Cpm_jz4780_chip::get_hdmi_frequency()
1.280 +{
1.281 + return get_hdmi_source_frequency() / get_hdmi_divider();
1.282 +}
1.283 +
1.284 // Clock frequency for the LCD0 controller.
1.285
1.286 uint32_t
1.287 @@ -653,6 +773,15 @@
1.288
1.289
1.290
1.291 +void
1.292 +Cpm_jz4780_chip::set_hdmi_frequency(uint32_t pclk)
1.293 +{
1.294 + // Switch to the video PLL and attempt to set the divider.
1.295 +
1.296 + set_hdmi_source(Source_pll_V);
1.297 + set_hdmi_divider(get_hdmi_source_frequency() / pclk);
1.298 +}
1.299 +
1.300 // Set the pixel frequency.
1.301 // Unlike the jz4740, HCLK/AHB0 is used as the device frequency, with the pixel
1.302 // frequency being based on the selected clock source (SCLK_A, MPLL or VPLL).
1.303 @@ -710,6 +839,18 @@
1.304
1.305
1.306 void
1.307 +jz4780_cpm_start_hdmi(void *cpm)
1.308 +{
1.309 + static_cast<Cpm_jz4780_chip *>(cpm)->start_hdmi();
1.310 +}
1.311 +
1.312 +void
1.313 +jz4780_cpm_stop_hdmi(void *cpm)
1.314 +{
1.315 + static_cast<Cpm_jz4780_chip *>(cpm)->stop_hdmi();
1.316 +}
1.317 +
1.318 +void
1.319 jz4780_cpm_start_lcd(void *cpm)
1.320 {
1.321 static_cast<Cpm_jz4780_chip *>(cpm)->start_lcd();
1.322 @@ -742,6 +883,12 @@
1.323 }
1.324
1.325 uint8_t
1.326 +jz4780_cpm_get_hdmi_divider(void *cpm)
1.327 +{
1.328 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_divider();
1.329 +}
1.330 +
1.331 +uint8_t
1.332 jz4780_cpm_get_lcd_pixel_divider(void *cpm)
1.333 {
1.334 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_divider();
1.335 @@ -774,6 +921,12 @@
1.336 }
1.337
1.338 uint8_t
1.339 +jz4780_cpm_get_hdmi_source(void *cpm)
1.340 +{
1.341 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source();
1.342 +}
1.343 +
1.344 +uint8_t
1.345 jz4780_cpm_get_lcd_source(void *cpm)
1.346 {
1.347 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source();
1.348 @@ -812,6 +965,12 @@
1.349 }
1.350
1.351 uint32_t
1.352 +jz4780_cpm_get_hdmi_source_frequency(void *cpm)
1.353 +{
1.354 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source_frequency();
1.355 +}
1.356 +
1.357 +uint32_t
1.358 jz4780_cpm_get_lcd_source_frequency(void *cpm)
1.359 {
1.360 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source_frequency();
1.361 @@ -862,6 +1021,12 @@
1.362 }
1.363
1.364 uint32_t
1.365 +jz4780_cpm_get_hdmi_frequency(void *cpm)
1.366 +{
1.367 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_frequency();
1.368 +}
1.369 +
1.370 +uint32_t
1.371 jz4780_cpm_get_lcd_pixel_frequency(void *cpm)
1.372 {
1.373 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_frequency();
1.374 @@ -906,6 +1071,12 @@
1.375
1.376
1.377 void
1.378 +jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk)
1.379 +{
1.380 + static_cast<Cpm_jz4780_chip *>(cpm)->set_hdmi_frequency(pclk);
1.381 +}
1.382 +
1.383 +void
1.384 jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk)
1.385 {
1.386 static_cast<Cpm_jz4780_chip *>(cpm)->set_lcd_pixel_frequency(pclk);