1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/conf/landfall-examples/mips-ci20-hdmi-i2c.cfg Fri May 22 00:17:25 2020 +0200 1.3 @@ -0,0 +1,29 @@ 1.4 +# this is a configuration to start 'ex_ci20_hdmi_i2c' 1.5 + 1.6 +local L4 = require("L4"); 1.7 + 1.8 +local l = L4.default_loader; 1.9 + 1.10 +local io_buses = 1.11 + { 1.12 + hdmi = l:new_channel(); 1.13 + }; 1.14 + 1.15 +l:start({ 1.16 + caps = { 1.17 + hdmi = io_buses.hdmi:svr(), 1.18 + icu = L4.Env.icu, 1.19 + sigma0 = L4.cast(L4.Proto.Factory, L4.Env.sigma0):create(L4.Proto.Sigma0), 1.20 + }, 1.21 + log = { "IO", "y" }, 1.22 + l4re_dbg = L4.Dbg.Warn, 1.23 + }, 1.24 + "rom/io -vvvv rom/hw_devices.io rom/mips-ci20-hdmi-i2c.io"); 1.25 + 1.26 +l:start({ 1.27 + caps = { 1.28 + icu = L4.Env.icu, 1.29 + vbus = io_buses.hdmi, 1.30 + }, 1.31 + }, 1.32 + "rom/ex_ci20_hdmi_i2c");
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/conf/landfall-examples/mips-ci20-hdmi-i2c.io Fri May 22 00:17:25 2020 +0200 2.3 @@ -0,0 +1,13 @@ 2.4 +-- vi:ft=lua 2.5 +-- configuration file for io 2.6 + 2.7 +local hw = Io.system_bus() 2.8 + 2.9 +local bus = Io.Vi.System_bus 2.10 +{ 2.11 + CPM = wrap(hw:match("jz4780-cpm")); 2.12 + GPIO = wrap(hw:match("jz4780-gpio")); 2.13 + HDMI = wrap(hw:match("jz4780-hdmi")); 2.14 +} 2.15 + 2.16 +Io.add_vbus("hdmi", bus)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/conf/landfall-examples/mips-ci20-hdmi-i2c.list Fri May 22 00:17:25 2020 +0200 3.3 @@ -0,0 +1,14 @@ 3.4 + 3.5 +modaddr 0x1100000 3.6 + 3.7 +entry mips-ci20-hdmi-i2c-example 3.8 +bootstrap bootstrap -serial 3.9 +kernel fiasco -serial_esc 3.10 +roottask moe rom/mips-ci20-hdmi-i2c.cfg 3.11 +module mips-ci20-hdmi-i2c.cfg 3.12 +module mips-ci20-hdmi-i2c.io 3.13 +module plat-mips-ci20/hw_devices.io 3.14 +module l4re 3.15 +module io 3.16 +module ned 3.17 +module ex_ci20_hdmi_i2c
4.1 --- a/pkg/devices/lib/cpm/include/cpm-jz4780.h Sat Jan 25 16:07:18 2020 +0100 4.2 +++ b/pkg/devices/lib/cpm/include/cpm-jz4780.h Fri May 22 00:17:25 2020 +0200 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 4.6 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk> 4.7 * 4.8 * This program is free software; you can redistribute it and/or 4.9 * modify it under the terms of the GNU General Public License as 4.10 @@ -63,6 +63,7 @@ 4.11 4.12 // Clock dividers. 4.13 4.14 + void set_hdmi_divider(uint16_t division); 4.15 void set_lcd_pixel_divider(uint16_t division); 4.16 4.17 // Clock control. 4.18 @@ -76,6 +77,7 @@ 4.19 // Clock sources. 4.20 4.21 void set_hclock2_source(uint8_t source); 4.22 + void set_hdmi_source(uint8_t source); 4.23 void set_lcd_source(uint8_t source); 4.24 4.25 public: 4.26 @@ -91,11 +93,15 @@ 4.27 uint8_t get_hclock0_divider(); 4.28 uint8_t get_hclock2_divider(); 4.29 uint8_t get_pclock_divider(); 4.30 + uint8_t get_hdmi_divider(); 4.31 uint8_t get_lcd_pixel_divider(); 4.32 uint8_t get_memory_divider(); 4.33 4.34 // Clock control. 4.35 4.36 + void start_hdmi(); 4.37 + void stop_hdmi(); 4.38 + 4.39 void start_lcd(); 4.40 void stop_lcd(); 4.41 4.42 @@ -112,6 +118,7 @@ 4.43 uint8_t get_cpu_source(); 4.44 uint8_t get_hclock0_source(); 4.45 uint8_t get_hclock2_source(); 4.46 + uint8_t get_hdmi_source(); 4.47 uint8_t get_lcd_source(); 4.48 uint8_t get_memory_source(); 4.49 uint8_t get_pclock_source(); 4.50 @@ -119,6 +126,7 @@ 4.51 uint32_t get_cpu_source_frequency(); 4.52 uint32_t get_hclock0_source_frequency(); 4.53 uint32_t get_hclock2_source_frequency(); 4.54 + uint32_t get_hdmi_source_frequency(); 4.55 uint32_t get_lcd_source_frequency(); 4.56 uint32_t get_memory_source_frequency(); 4.57 uint32_t get_pclock_source_frequency(); 4.58 @@ -128,6 +136,7 @@ 4.59 uint32_t get_cpu_frequency(); 4.60 uint32_t get_hclock0_frequency(); 4.61 uint32_t get_hclock2_frequency(); 4.62 + uint32_t get_hdmi_frequency(); 4.63 uint32_t get_lcd_pixel_frequency(); 4.64 uint32_t get_memory_frequency(); 4.65 uint32_t get_pclock_frequency(); 4.66 @@ -137,6 +146,7 @@ 4.67 uint32_t get_mpll_frequency(); 4.68 uint32_t get_vpll_frequency(); 4.69 4.70 + void set_hdmi_frequency(uint32_t pclk); 4.71 void set_lcd_pixel_frequency(uint32_t pclk); 4.72 void set_lcd_frequencies(uint32_t pclk, uint8_t multiplier); 4.73 void set_pll_parameters(uint32_t pll_reg, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); 4.74 @@ -157,24 +167,30 @@ 4.75 int jz4780_cpm_have_clock(void *cpm); 4.76 void jz4780_cpm_start_clock(void *cpm); 4.77 4.78 +void jz4780_cpm_start_hdmi(void *cpm); 4.79 +void jz4780_cpm_stop_hdmi(void *cpm); 4.80 + 4.81 void jz4780_cpm_start_lcd(void *cpm); 4.82 void jz4780_cpm_stop_lcd(void *cpm); 4.83 4.84 uint8_t jz4780_cpm_get_cpu_divider(void *cpm); 4.85 uint8_t jz4780_cpm_get_hclock0_divider(void *cpm); 4.86 uint8_t jz4780_cpm_get_hclock2_divider(void *cpm); 4.87 +uint8_t jz4780_cpm_get_hdmi_divider(void *cpm); 4.88 uint8_t jz4780_cpm_get_lcd_pixel_divider(void *cpm); 4.89 uint8_t jz4780_cpm_get_memory_divider(void *cpm); 4.90 uint8_t jz4780_cpm_get_pclock_divider(void *cpm); 4.91 4.92 uint8_t jz4780_cpm_get_hclock0_source(void *cpm); 4.93 uint8_t jz4780_cpm_get_hclock2_source(void *cpm); 4.94 +uint8_t jz4780_cpm_get_hdmi_source(void *cpm); 4.95 uint8_t jz4780_cpm_get_lcd_source(void *cpm); 4.96 uint8_t jz4780_cpm_get_memory_source(void *cpm); 4.97 uint8_t jz4780_cpm_get_pclock_source(void *cpm); 4.98 4.99 uint32_t jz4780_cpm_get_hclock0_source_frequency(void *cpm); 4.100 uint32_t jz4780_cpm_get_hclock2_source_frequency(void *cpm); 4.101 +uint32_t jz4780_cpm_get_hdmi_source_frequency(void *cpm); 4.102 uint32_t jz4780_cpm_get_lcd_source_frequency(void *cpm); 4.103 uint32_t jz4780_cpm_get_memory_source_frequency(void *cpm); 4.104 uint32_t jz4780_cpm_get_pclock_source_frequency(void *cpm); 4.105 @@ -187,6 +203,7 @@ 4.106 uint32_t jz4780_cpm_get_cpu_frequency(void *cpm); 4.107 uint32_t jz4780_cpm_get_hclock0_frequency(void *cpm); 4.108 uint32_t jz4780_cpm_get_hclock2_frequency(void *cpm); 4.109 +uint32_t jz4780_cpm_get_hdmi_frequency(void *cpm); 4.110 uint32_t jz4780_cpm_get_lcd_pixel_frequency(void *cpm); 4.111 uint32_t jz4780_cpm_get_memory_frequency(void *cpm); 4.112 uint32_t jz4780_cpm_get_pclock_frequency(void *cpm); 4.113 @@ -196,6 +213,7 @@ 4.114 uint32_t jz4780_cpm_get_mpll_frequency(void *cpm); 4.115 uint32_t jz4780_cpm_get_vpll_frequency(void *cpm); 4.116 4.117 +void jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk); 4.118 void jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk); 4.119 void jz4780_cpm_set_mpll_parameters(void *cpm, uint16_t multiplier, uint8_t in_divider, uint8_t out_divider); 4.120
5.1 --- a/pkg/devices/lib/cpm/src/jz4780.cc Sat Jan 25 16:07:18 2020 +0100 5.2 +++ b/pkg/devices/lib/cpm/src/jz4780.cc Fri May 22 00:17:25 2020 +0200 5.3 @@ -3,7 +3,7 @@ 5.4 * provided by the jz4780 and related SoCs. The power management 5.5 * functionality could be exposed using a separate driver. 5.6 * 5.7 - * Copyright (C) 2017, 2018 Paul Boddie <paul@boddie.org.uk> 5.8 + * Copyright (C) 2017, 2018, 2020 Paul Boddie <paul@boddie.org.uk> 5.9 * 5.10 * This program is free software; you can redistribute it and/or 5.11 * modify it under the terms of the GNU General Public License as 5.12 @@ -48,6 +48,12 @@ 5.13 Msc_divider2 = 0x0a8, // MSC2CDR 5.14 Uhc_divider = 0x06c, // UHCCDR 5.15 Ssi_divider = 0x074, // SSICDR 5.16 + 5.17 + // ... 5.18 + 5.19 + Hdmi_divider = 0x08c, // HDMICDR 5.20 + 5.21 + // ... 5.22 }; 5.23 5.24 enum Clock_bits : unsigned 5.25 @@ -78,23 +84,39 @@ 5.26 Clock_source_ddr = 30, // DCS 5.27 Clock_source_i2s = 31, // I2CS 5.28 Clock_source_lcd = 30, // LPCS 5.29 + Clock_source_hdmi = 30, // HPCS 5.30 }; 5.31 5.32 enum Clock_sources : unsigned 5.33 { 5.34 + // Main clock sources. 5.35 + 5.36 Source_pll_A = 1, // APLL 5.37 Source_external = 2, // EXCLK 5.38 Source_realtime = 3, // RTCLK 5.39 - Source_main_frequency = 1, // SCLK_A 5.40 - Source_pll_M = 2, // MPLL 5.41 - Source_pll_E = 3, // EPLL 5.42 - Source_pll_V = 3, // VPLL 5.43 + 5.44 + // Stoppable clock sources. 5.45 + 5.46 + Source_mux_stopped = 0, 5.47 + Source_mux_main = 1, // SCLK_A 5.48 + Source_mux_pll_M = 2, // MPLL 5.49 + Source_mux_pll_E = 3, // EPLL 5.50 + Source_mux_realtime = 3, // RTCLK (TCK) 5.51 + 5.52 + // Unstoppable clock sources. 5.53 + 5.54 + Source_main = 0, // SCLK_A 5.55 + Source_pll_M = 1, // MPLL 5.56 + Source_pll_E = 2, // EPLL 5.57 + Source_pll_V = 2, // VPLL 5.58 + Source_otg_phy = 3, // OTG_PHY 5.59 }; 5.60 5.61 enum Clock_gate_bits : unsigned 5.62 { 5.63 Clock_gate_lcd = 28, // LCD (in CLKGR0) 5.64 Clock_gate_tve = 27, // TVE (in CLKGR0) 5.65 + Clock_gate_hdmi = 9, // HDMI (in CLKGR1) 5.66 Clock_gate_smb4 = 12, // SMB4 (in CLKGR1) 5.67 Clock_gate_smb3 = 0, // SMB3 (in CLKGR1) 5.68 Clock_gate_smb2 = 25, // SMB2 (in CLKGR0) 5.69 @@ -114,14 +136,23 @@ 5.70 enum Divider_bits : unsigned 5.71 { 5.72 Ddr_divider_value = 0, // DDRCDR 5.73 + Hdmi_divider_value = 0, // HDMICDR 5.74 Lcd_divider_value = 0, // LPCDR 5.75 }; 5.76 5.77 -enum Lcd_clock_bits : unsigned 5.78 +enum Lcd_clock_values : unsigned 5.79 { 5.80 - Lcd_change_enable = 0x1000, // CE_LCD 5.81 - Lcd_change_busy = 0x0800, // LCD_BUSY 5.82 - Lcd_clock_stop = 0x0400, // LCD_STOP 5.83 + Lcd_change_enable = 0x10000000, // CE_LCD 5.84 + Lcd_change_busy = 0x08000000, // LCD_BUSY 5.85 + Lcd_clock_stop = 0x04000000, // LCD_STOP 5.86 +}; 5.87 + 5.88 +enum Hdmi_divider_values : unsigned 5.89 +{ 5.90 + Hdmi_select_mask = 0xc0000000, // HPCS 5.91 + Hdmi_change_enable = 0x20000000, // CE_HDMI 5.92 + Hdmi_change_busy = 0x10000000, // HDMI_BUSY 5.93 + Hdmi_clock_stop = 0x08000000, // HDMI_STOP 5.94 }; 5.95 5.96 5.97 @@ -313,6 +344,14 @@ 5.98 return _get_divider(Clock_control, 0xf, Clock_pclock_divider); 5.99 } 5.100 5.101 +// HDMI clock divider. 5.102 + 5.103 +uint8_t 5.104 +Cpm_jz4780_chip::get_hdmi_divider() 5.105 +{ 5.106 + return get_field(Hdmi_divider, 0xff, Hdmi_divider_value) + 1; 5.107 +} 5.108 + 5.109 // LCD clock (LPCLK) divider for LCD0 pixel clock. 5.110 5.111 uint8_t 5.112 @@ -329,6 +368,28 @@ 5.113 return _get_divider(Ddr_divider, 0xf, Ddr_divider_value); 5.114 } 5.115 5.116 +// HDMI clock divider. 5.117 + 5.118 +void 5.119 +Cpm_jz4780_chip::set_hdmi_divider(uint16_t division) 5.120 +{ 5.121 + if ((division < 1) || (division > 256)) 5.122 + return; 5.123 + 5.124 + // Enable change. 5.125 + 5.126 + _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable; 5.127 + 5.128 + // Set the divider. 5.129 + 5.130 + set_field(Hdmi_divider, 0xff, Hdmi_divider_value, division - 1); 5.131 + 5.132 + // Restart clock and disable change. 5.133 + 5.134 + while (_regs[Hdmi_divider] & Hdmi_change_busy); 5.135 + _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~Hdmi_change_enable; 5.136 +} 5.137 + 5.138 // LCD pixel clock divider. 5.139 // NOTE: This only supports the first LCD peripheral. 5.140 5.141 @@ -357,6 +418,18 @@ 5.142 // Clock gating control. 5.143 5.144 void 5.145 +Cpm_jz4780_chip::start_hdmi() 5.146 +{ 5.147 + _regs[Clock_gate1] = _regs[Clock_gate1] & ~(1 << Clock_gate_hdmi); 5.148 +} 5.149 + 5.150 +void 5.151 +Cpm_jz4780_chip::stop_hdmi() 5.152 +{ 5.153 + _regs[Clock_gate1] = _regs[Clock_gate1] | (1 << Clock_gate_hdmi); 5.154 +} 5.155 + 5.156 +void 5.157 Cpm_jz4780_chip::start_lcd() 5.158 { 5.159 _regs[Clock_gate0] = _regs[Clock_gate0] & ~(1 << Clock_gate_lcd); 5.160 @@ -415,9 +488,9 @@ 5.161 { 5.162 switch (get_memory_source()) 5.163 { 5.164 - case Source_main_frequency: 5.165 + case Source_mux_main: 5.166 return get_main_frequency(); 5.167 - case Source_pll_M: 5.168 + case Source_mux_pll_M: 5.169 return get_pll_frequency(Pll_control_M); 5.170 default: 5.171 return 0; 5.172 @@ -435,11 +508,11 @@ 5.173 { 5.174 switch (get_cpu_source()) 5.175 { 5.176 - case Source_main_frequency: 5.177 + case Source_mux_main: 5.178 return get_main_frequency(); 5.179 - case Source_pll_M: 5.180 + case Source_mux_pll_M: 5.181 return get_pll_frequency(Pll_control_M); 5.182 - case Source_pll_E: 5.183 + case Source_mux_pll_E: 5.184 return get_pll_frequency(Pll_control_E); 5.185 default: 5.186 return 0; 5.187 @@ -457,11 +530,11 @@ 5.188 { 5.189 switch (get_hclock0_source()) 5.190 { 5.191 - case Source_main_frequency: 5.192 + case Source_mux_main: 5.193 return get_main_frequency(); 5.194 - case Source_pll_M: 5.195 + case Source_mux_pll_M: 5.196 return get_pll_frequency(Pll_control_M); 5.197 - case Source_pll_E: 5.198 + case Source_mux_pll_E: 5.199 return get_pll_frequency(Pll_control_E); 5.200 default: 5.201 return 0; 5.202 @@ -479,11 +552,11 @@ 5.203 { 5.204 switch (get_hclock2_source()) 5.205 { 5.206 - case Source_main_frequency: 5.207 + case Source_mux_main: 5.208 return get_main_frequency(); 5.209 - case Source_pll_M: 5.210 + case Source_mux_pll_M: 5.211 return get_pll_frequency(Pll_control_M); 5.212 - case Source_realtime: 5.213 + case Source_mux_realtime: 5.214 return _rtclk_freq; // "TCK" in the manual, RTCLK in Linux driver code 5.215 default: 5.216 return 0; 5.217 @@ -497,6 +570,45 @@ 5.218 } 5.219 5.220 uint8_t 5.221 +Cpm_jz4780_chip::get_hdmi_source() 5.222 +{ 5.223 + return get_field(Hdmi_divider, 0x3, Clock_source_hdmi); 5.224 +} 5.225 + 5.226 +uint32_t 5.227 +Cpm_jz4780_chip::get_hdmi_source_frequency() 5.228 +{ 5.229 + switch (get_hdmi_source()) 5.230 + { 5.231 + case Source_main: 5.232 + return get_main_frequency(); 5.233 + case Source_pll_M: 5.234 + return get_pll_frequency(Pll_control_M); 5.235 + case Source_pll_V: 5.236 + return get_pll_frequency(Pll_control_V); 5.237 + default: 5.238 + return 0; 5.239 + } 5.240 +} 5.241 + 5.242 +void 5.243 +Cpm_jz4780_chip::set_hdmi_source(uint8_t source) 5.244 +{ 5.245 + // Stop clock and enable change. 5.246 + 5.247 + _regs[Hdmi_divider] = _regs[Hdmi_divider] | Hdmi_change_enable | Hdmi_clock_stop; 5.248 + 5.249 + // Set the source. 5.250 + 5.251 + set_field(Hdmi_divider, 0x03, Clock_source_hdmi, source); 5.252 + 5.253 + // Restart clock and disable change. 5.254 + 5.255 + while (_regs[Hdmi_divider] & Hdmi_change_busy); 5.256 + _regs[Hdmi_divider] = _regs[Hdmi_divider] & ~(Hdmi_change_enable | Hdmi_clock_stop); 5.257 +} 5.258 + 5.259 +uint8_t 5.260 Cpm_jz4780_chip::get_lcd_source() 5.261 { 5.262 return get_field(Lcd_divider0, 0x3, Clock_source_lcd); 5.263 @@ -507,7 +619,7 @@ 5.264 { 5.265 switch (get_lcd_source()) 5.266 { 5.267 - case Source_main_frequency: 5.268 + case Source_main: 5.269 return get_main_frequency(); 5.270 case Source_pll_M: 5.271 return get_pll_frequency(Pll_control_M); 5.272 @@ -611,6 +723,14 @@ 5.273 return get_pclock_source_frequency() / get_pclock_divider(); 5.274 } 5.275 5.276 +// Clock frequency for the HDMI peripheral. 5.277 + 5.278 +uint32_t 5.279 +Cpm_jz4780_chip::get_hdmi_frequency() 5.280 +{ 5.281 + return get_hdmi_source_frequency() / get_hdmi_divider(); 5.282 +} 5.283 + 5.284 // Clock frequency for the LCD0 controller. 5.285 5.286 uint32_t 5.287 @@ -653,6 +773,15 @@ 5.288 5.289 5.290 5.291 +void 5.292 +Cpm_jz4780_chip::set_hdmi_frequency(uint32_t pclk) 5.293 +{ 5.294 + // Switch to the video PLL and attempt to set the divider. 5.295 + 5.296 + set_hdmi_source(Source_pll_V); 5.297 + set_hdmi_divider(get_hdmi_source_frequency() / pclk); 5.298 +} 5.299 + 5.300 // Set the pixel frequency. 5.301 // Unlike the jz4740, HCLK/AHB0 is used as the device frequency, with the pixel 5.302 // frequency being based on the selected clock source (SCLK_A, MPLL or VPLL). 5.303 @@ -710,6 +839,18 @@ 5.304 5.305 5.306 void 5.307 +jz4780_cpm_start_hdmi(void *cpm) 5.308 +{ 5.309 + static_cast<Cpm_jz4780_chip *>(cpm)->start_hdmi(); 5.310 +} 5.311 + 5.312 +void 5.313 +jz4780_cpm_stop_hdmi(void *cpm) 5.314 +{ 5.315 + static_cast<Cpm_jz4780_chip *>(cpm)->stop_hdmi(); 5.316 +} 5.317 + 5.318 +void 5.319 jz4780_cpm_start_lcd(void *cpm) 5.320 { 5.321 static_cast<Cpm_jz4780_chip *>(cpm)->start_lcd(); 5.322 @@ -742,6 +883,12 @@ 5.323 } 5.324 5.325 uint8_t 5.326 +jz4780_cpm_get_hdmi_divider(void *cpm) 5.327 +{ 5.328 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_divider(); 5.329 +} 5.330 + 5.331 +uint8_t 5.332 jz4780_cpm_get_lcd_pixel_divider(void *cpm) 5.333 { 5.334 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_divider(); 5.335 @@ -774,6 +921,12 @@ 5.336 } 5.337 5.338 uint8_t 5.339 +jz4780_cpm_get_hdmi_source(void *cpm) 5.340 +{ 5.341 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source(); 5.342 +} 5.343 + 5.344 +uint8_t 5.345 jz4780_cpm_get_lcd_source(void *cpm) 5.346 { 5.347 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source(); 5.348 @@ -812,6 +965,12 @@ 5.349 } 5.350 5.351 uint32_t 5.352 +jz4780_cpm_get_hdmi_source_frequency(void *cpm) 5.353 +{ 5.354 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_source_frequency(); 5.355 +} 5.356 + 5.357 +uint32_t 5.358 jz4780_cpm_get_lcd_source_frequency(void *cpm) 5.359 { 5.360 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_source_frequency(); 5.361 @@ -862,6 +1021,12 @@ 5.362 } 5.363 5.364 uint32_t 5.365 +jz4780_cpm_get_hdmi_frequency(void *cpm) 5.366 +{ 5.367 + return static_cast<Cpm_jz4780_chip *>(cpm)->get_hdmi_frequency(); 5.368 +} 5.369 + 5.370 +uint32_t 5.371 jz4780_cpm_get_lcd_pixel_frequency(void *cpm) 5.372 { 5.373 return static_cast<Cpm_jz4780_chip *>(cpm)->get_lcd_pixel_frequency(); 5.374 @@ -906,6 +1071,12 @@ 5.375 5.376 5.377 void 5.378 +jz4780_cpm_set_hdmi_frequency(void *cpm, uint32_t pclk) 5.379 +{ 5.380 + static_cast<Cpm_jz4780_chip *>(cpm)->set_hdmi_frequency(pclk); 5.381 +} 5.382 + 5.383 +void 5.384 jz4780_cpm_set_lcd_pixel_frequency(void *cpm, uint32_t pclk) 5.385 { 5.386 static_cast<Cpm_jz4780_chip *>(cpm)->set_lcd_pixel_frequency(pclk);
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/pkg/devices/lib/hdmi/Makefile Fri May 22 00:17:25 2020 +0200 6.3 @@ -0,0 +1,8 @@ 6.4 +PKGDIR ?= ../.. 6.5 +L4DIR ?= $(PKGDIR)/../.. 6.6 + 6.7 +TARGET := include src 6.8 + 6.9 +include $(L4DIR)/mk/subdir.mk 6.10 + 6.11 +src: include
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/pkg/devices/lib/hdmi/include/Makefile Fri May 22 00:17:25 2020 +0200 7.3 @@ -0,0 +1,4 @@ 7.4 +PKGDIR = ../../.. 7.5 +L4DIR ?= $(PKGDIR)/../.. 7.6 + 7.7 +include $(L4DIR)/mk/include.mk
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/pkg/devices/lib/hdmi/include/hdmi-jz4780.h Fri May 22 00:17:25 2020 +0200 8.3 @@ -0,0 +1,90 @@ 8.4 +/* 8.5 + * JZ4780 HDMI peripheral support. 8.6 + * 8.7 + * Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk> 8.8 + * 8.9 + * This program is free software; you can redistribute it and/or 8.10 + * modify it under the terms of the GNU General Public License as 8.11 + * published by the Free Software Foundation; either version 2 of 8.12 + * the License, or (at your option) any later version. 8.13 + * 8.14 + * This program is distributed in the hope that it will be useful, 8.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 8.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8.17 + * GNU General Public License for more details. 8.18 + * 8.19 + * You should have received a copy of the GNU General Public License 8.20 + * along with this program; if not, write to the Free Software 8.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 8.22 + * Boston, MA 02110-1301, USA 8.23 + */ 8.24 + 8.25 +#pragma once 8.26 + 8.27 +#include <l4/sys/types.h> 8.28 +#include <stdint.h> 8.29 + 8.30 + 8.31 + 8.32 +#ifdef __cplusplus 8.33 + 8.34 +#include <l4/devices/hw_mmio_register_block.h> 8.35 + 8.36 +// HDMI device control. 8.37 + 8.38 +class Hdmi_jz4780_chip 8.39 +{ 8.40 +private: 8.41 + l4_addr_t _start, _end; 8.42 + l4_cap_idx_t _irq; 8.43 + Hw::Register_block<8> _regs; 8.44 + 8.45 + // Identification. 8.46 + 8.47 + uint16_t _version; 8.48 + 8.49 + // Transfer properties. 8.50 + 8.51 + bool _segment_read; 8.52 + uint8_t _device_register; 8.53 + 8.54 +protected: 8.55 + void get_identification(); 8.56 + 8.57 + void int_init(); 8.58 + 8.59 + void i2c_init(); 8.60 + long i2c_wait(); 8.61 + 8.62 +public: 8.63 + Hdmi_jz4780_chip(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq); 8.64 + 8.65 + void get_version(uint8_t *major, uint16_t *minor); 8.66 + 8.67 + int i2c_read(uint8_t *buf, unsigned int length); 8.68 + void i2c_set_address(uint8_t address); 8.69 + void i2c_set_segment(uint8_t segment); 8.70 + void i2c_set_register(uint8_t device_register); 8.71 +}; 8.72 + 8.73 +#endif /* __cplusplus */ 8.74 + 8.75 + 8.76 + 8.77 +/* C language interface. */ 8.78 + 8.79 +EXTERN_C_BEGIN 8.80 + 8.81 +void *jz4780_hdmi_init(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq); 8.82 + 8.83 +void jz4780_hdmi_get_version(void *hdmi, uint8_t *major, uint16_t *minor); 8.84 + 8.85 +int jz4780_hdmi_i2c_read(void *hdmi, uint8_t *buf, unsigned int length); 8.86 + 8.87 +void jz4780_hdmi_i2c_set_address(void *hdmi, uint8_t address); 8.88 + 8.89 +void jz4780_hdmi_i2c_set_segment(void *hdmi, uint8_t segment); 8.90 + 8.91 +void jz4780_hdmi_i2c_set_register(void *hdmi, uint8_t device_register); 8.92 + 8.93 +EXTERN_C_END
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/pkg/devices/lib/hdmi/src/Makefile Fri May 22 00:17:25 2020 +0200 9.3 @@ -0,0 +1,13 @@ 9.4 +PKGDIR ?= ../../.. 9.5 +L4DIR ?= $(PKGDIR)/../.. 9.6 + 9.7 +TARGET = libhdmi.o.a 9.8 +PC_FILENAME := libdrivers-hdmi 9.9 + 9.10 +SRC_CC := jz4780.cc 9.11 + 9.12 +PRIVATE_INCDIR += $(PKGDIR)/lib/hdmi/include 9.13 + 9.14 +REQUIRES_LIBS := l4re_c l4re_c-util libdrivers-common 9.15 + 9.16 +include $(L4DIR)/mk/lib.mk
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/pkg/devices/lib/hdmi/src/jz4780.cc Fri May 22 00:17:25 2020 +0200 10.3 @@ -0,0 +1,362 @@ 10.4 +/* 10.5 + * JZ4780 HDMI peripheral support. 10.6 + * 10.7 + * Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk> 10.8 + * 10.9 + * This program is free software; you can redistribute it and/or 10.10 + * modify it under the terms of the GNU General Public License as 10.11 + * published by the Free Software Foundation; either version 2 of 10.12 + * the License, or (at your option) any later version. 10.13 + * 10.14 + * This program is distributed in the hope that it will be useful, 10.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10.17 + * GNU General Public License for more details. 10.18 + * 10.19 + * You should have received a copy of the GNU General Public License 10.20 + * along with this program; if not, write to the Free Software 10.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, 10.22 + * Boston, MA 02110-1301, USA 10.23 + */ 10.24 + 10.25 +#include <l4/devices/hdmi-jz4780.h> 10.26 +#include <l4/devices/hw_mmio_register_block.h> 10.27 + 10.28 +#include <l4/sys/irq.h> 10.29 +#include <l4/util/util.h> 10.30 + 10.31 +#include <cstdio> 10.32 + 10.33 +/* 10.34 +I2C pins: 10.35 + 10.36 +HDMI: PF25/SMB4_SDA/DDCSDA, PF24/SMB4_SCK/DDCSCK 10.37 + 10.38 +See: http://mipscreator.imgtec.com/CI20/hardware/board/ci20_jz4780_v2.0.pdf 10.39 +*/ 10.40 + 10.41 +enum Regs 10.42 +{ 10.43 + // Identification. 10.44 + 10.45 + Design_id = 0x000, // DESIGN_ID 10.46 + Revision_id = 0x001, // REVISION_ID 10.47 + Product_id0 = 0x002, // PRODUCT_ID0 10.48 + Product_id1 = 0x003, // PRODUCT_ID1 10.49 + Config_id0 = 0x004, // CONFIG_ID0 10.50 + Config_id1 = 0x005, // CONFIG_ID1 10.51 + Config_id2 = 0x006, // CONFIG_ID2 10.52 + Config_id3 = 0x007, // CONFIG_ID3 10.53 + 10.54 + // Top-level interrupt control. 10.55 + 10.56 + Int_mask = 0x1ff, // MUTE 10.57 + 10.58 + // Interrupt status and mask for various functions. 10.59 + 10.60 + Fc_int_status0 = 0x100, // FC_STAT0 10.61 + Fc_int_status1 = 0x101, // FC_STAT1 10.62 + Fc_int_status2 = 0x102, // FC_STAT2 10.63 + As_int_status = 0x103, // AS_STAT0 10.64 + Phy_int_status = 0x104, // PHY_STAT0 10.65 + Cec_int_status = 0x106, // CEC_STAT0 10.66 + Vp_int_status = 0x107, // VP_STAT0 10.67 + Ahb_dma_audio_int_status = 0x109, // AHBDMAAUD_STAT0 10.68 + 10.69 + Fc_int_mask0 = 0x180, // MUTE_FC_STAT0 10.70 + Fc_int_mask1 = 0x181, // MUTE_FC_STAT1 10.71 + Fc_int_mask2 = 0x182, // MUTE_FC_STAT2 10.72 + As_int_mask = 0x183, // MUTE_AS_STAT0 10.73 + Phy_int_mask = 0x184, // MUTE_PHY_STAT0 10.74 + Cec_int_mask = 0x186, // MUTE_CEC_STAT0 10.75 + Vp_int_mask = 0x187, // MUTE_VP_STAT0 10.76 + Ahb_dma_audio_int_mask = 0x189, // MUTE_AHBDMAAUD_STAT0 10.77 + 10.78 + // I2C for E-DDC. 10.79 + 10.80 + I2c_int_status = 0x105, // I2CM_STAT0 10.81 + I2c_int_mask = 0x185, // MUTE_I2CM_STAT0 10.82 + 10.83 + I2c_device_address = 0x7e00, // I2CM_SLAVE 10.84 + I2c_register = 0x7e01, // I2CM_ADDRESS 10.85 + I2c_data_out = 0x7e02, // I2CM_DATAO 10.86 + I2c_data_in = 0x7e03, // I2CM_DATAI 10.87 + I2c_operation = 0x7e04, // I2CM_OPERATION 10.88 + I2c_int_config0 = 0x7e05, // I2CM_INT 10.89 + I2c_int_config1 = 0x7e06, // I2CM_CTLINT 10.90 + I2c_divider = 0x7e07, // I2CM_DIV 10.91 + I2c_segment_address = 0x7e08, // I2CM_SEGADDR 10.92 + I2c_software_reset = 0x7e09, // I2CM_SOFTRSTZ 10.93 + I2c_segment_pointer = 0x7e0a, // I2CM_SEGPTR 10.94 + 10.95 + // I2C for PHY. 10.96 + 10.97 + I2c_phy_int_status = 0x108, // I2CMPHY_STAT0 10.98 + I2c_phy_int_mask = 0x188, // MUTE_I2CMPHY_STAT0 10.99 + 10.100 + I2c_phy_int_config0 = 0x3027, // PHY_I2CM_INT_ADDR 10.101 + I2c_phy_int_config1 = 0x3028, // PHY_I2CM_CTLINT_ADDR 10.102 +}; 10.103 + 10.104 +// Identification values. 10.105 + 10.106 +enum Product_id_values : unsigned 10.107 +{ 10.108 + Product_id0_transmitter = 0xa0, // PRODUCT_ID0_HDMI_TX 10.109 + 10.110 + Product_id1_hdcp = 0xc0, // PRODUCT_ID1_HDCP 10.111 + Product_id1_receiver = 0x02, // PRODUCT_ID1_HDMI_RX 10.112 + Product_id1_transmitter = 0x01, // PRODUCT_ID1_HDMI_TX 10.113 +}; 10.114 + 10.115 +// Configuration values. 10.116 + 10.117 +enum Config_id_values : unsigned 10.118 +{ 10.119 + Config_id0_i2s = 0x10, // CONFIG0_I2S 10.120 + Config_id0_cec = 0x02, // CONFIG0_CEC 10.121 + 10.122 + Config_id1_ahb = 0x01, // CONFIG1_AHB 10.123 + 10.124 + Config2_dwc_hdmi_tx_phy = 0x00, // DWC_HDMI_TX_PHY 10.125 + Config2_dwc_mhl_phy_heac = 0xb2, // DWC_MHL_PHY_HEAC 10.126 + Config2_dwc_mhl_phy = 0xc2, // DWC_MHL_PHY 10.127 + Config2_dwc_hdmi_3d_tx_phy_heac = 0xe2, // DWC_HDMI_3D_TX_PHY_HEAC 10.128 + Config2_dwc_hdmi_3d_tx_phy = 0xf2, // DWC_HDMI_3D_TX_PHY 10.129 + Config2_dwc_hdmi20_tx_phy = 0xf3, // DWC_HDMI20_TX_PHY 10.130 + Config2_vendor_phy = 0xfe, // VENDOR_PHY 10.131 + 10.132 + Config_id3_ahb_audio_dma = 0x02, // CONFIG3_AHBAUDDMA 10.133 + Config_id3_gp_audio = 0x01, // CONFIG3_GPAUD 10.134 +}; 10.135 + 10.136 +// Status and mask bits. 10.137 + 10.138 +enum Int_mask_bits : unsigned 10.139 +{ 10.140 + Int_mask_wakeup = 0x2, 10.141 + Int_mask_all = 0x1, 10.142 +}; 10.143 + 10.144 +enum I2c_int_status_bits : unsigned 10.145 +{ 10.146 + I2c_int_status_done = 0x2, 10.147 + I2c_int_status_error = 0x1, 10.148 +}; 10.149 + 10.150 +// I2C operation bits. 10.151 + 10.152 +enum I2c_operation_bits : unsigned 10.153 +{ 10.154 + I2c_operation_write = 0x10, 10.155 + I2c_operation_segment_read = 0x2, 10.156 + I2c_operation_read = 0x1, 10.157 +}; 10.158 + 10.159 +// Interrupt configuration bits. 10.160 + 10.161 +enum I2c_int_config0_bits : unsigned 10.162 +{ 10.163 + I2c_int_config_done_polarity = 0x8, 10.164 + I2c_int_config_done_mask = 0x4, 10.165 +}; 10.166 + 10.167 +enum I2c_int_config1_bits : unsigned 10.168 +{ 10.169 + I2c_int_config_nack_polarity = 0x80, 10.170 + I2c_int_config_nack_mask = 0x40, 10.171 + I2c_int_config_arb_polarity = 0x8, 10.172 + I2c_int_config_arb_mask = 0x4, 10.173 +}; 10.174 + 10.175 + 10.176 + 10.177 +// Initialise the HDMI peripheral. 10.178 + 10.179 +Hdmi_jz4780_chip::Hdmi_jz4780_chip(l4_addr_t start, l4_addr_t end, 10.180 + l4_cap_idx_t irq) 10.181 +: _start(start), _end(end), _irq(irq) 10.182 +{ 10.183 + // 8-bit registers with 2-bit address shifting. 10.184 + 10.185 + _regs = new Hw::Mmio_register_block<8>(start, 2); 10.186 + 10.187 + _segment_read = false; 10.188 + _device_register = 0; 10.189 + 10.190 + get_identification(); 10.191 + int_init(); 10.192 + i2c_init(); 10.193 +} 10.194 + 10.195 +void Hdmi_jz4780_chip::get_identification() 10.196 +{ 10.197 + _version = (_regs[Design_id] << 8) | _regs[Revision_id]; 10.198 +} 10.199 + 10.200 +void Hdmi_jz4780_chip::get_version(uint8_t *major, uint16_t *minor) 10.201 +{ 10.202 + *major = _version >> 12; 10.203 + *minor = _version & 0xfff; 10.204 +} 10.205 + 10.206 +void Hdmi_jz4780_chip::int_init() 10.207 +{ 10.208 + // Disable interrupts. 10.209 + 10.210 + _regs[Int_mask] = _regs[Int_mask] | (Int_mask_wakeup | Int_mask_all); 10.211 + 10.212 + // Mask all interrupts. 10.213 + 10.214 + _regs[Fc_int_mask0] = 0xff; 10.215 + _regs[Fc_int_mask1] = 0xff; 10.216 + _regs[Fc_int_mask2] = 0xff; 10.217 + _regs[As_int_mask] = 0xff; 10.218 + _regs[Phy_int_mask] = 0xff; 10.219 + _regs[I2c_int_mask] = 0xff; 10.220 + _regs[Cec_int_mask] = 0xff; 10.221 + _regs[Vp_int_mask] = 0xff; 10.222 + _regs[I2c_phy_int_mask] = 0xff; 10.223 + _regs[Ahb_dma_audio_int_mask] = 0xff; 10.224 + 10.225 + // Enable interrupts. 10.226 + 10.227 + _regs[Int_mask] = _regs[Int_mask] & ~(Int_mask_wakeup | Int_mask_all); 10.228 +} 10.229 + 10.230 +void Hdmi_jz4780_chip::i2c_init() 10.231 +{ 10.232 + // Set PHY interrupt priorities. 10.233 + 10.234 + _regs[I2c_phy_int_config0] = I2c_int_config_done_polarity; 10.235 + _regs[I2c_phy_int_config1] = I2c_int_config_nack_polarity | 10.236 + I2c_int_config_arb_polarity; 10.237 + 10.238 + // Software reset. 10.239 + 10.240 + _regs[I2c_software_reset] = 0; 10.241 + 10.242 + // Standard mode (100kHz). 10.243 + 10.244 + _regs[I2c_divider] = 0; 10.245 + 10.246 + // Set interrupt polarities. 10.247 + 10.248 + _regs[I2c_int_config0] = I2c_int_config_done_polarity; 10.249 + _regs[I2c_int_config1] = I2c_int_config_nack_polarity | 10.250 + I2c_int_config_arb_polarity; 10.251 + 10.252 + // Clear and mask/mute interrupts. 10.253 + 10.254 + _regs[I2c_int_status] = I2c_int_status_done | I2c_int_status_error; 10.255 + _regs[I2c_int_mask] = I2c_int_status_done | I2c_int_status_error; 10.256 +} 10.257 + 10.258 +long Hdmi_jz4780_chip::i2c_wait() 10.259 +{ 10.260 + long err; 10.261 + 10.262 + // Wait for around 1s. 10.263 + 10.264 + l4_msgtag_t tag = l4_irq_receive(_irq, L4_IPC_NEVER); 10.265 + 10.266 + err = l4_ipc_error(tag, l4_utcb()); 10.267 + if (err) 10.268 + return err; 10.269 + 10.270 + // Test for an error condition. 10.271 + 10.272 + if (_regs[I2c_int_status] & I2c_int_status_error) 10.273 + return -L4_EIO; 10.274 + 10.275 + _regs[I2c_int_status] = _regs[I2c_int_status] | I2c_int_status_done; 10.276 + 10.277 + return L4_EOK; 10.278 +} 10.279 + 10.280 +int Hdmi_jz4780_chip::i2c_read(uint8_t *buf, unsigned int length) 10.281 +{ 10.282 + unsigned int i; 10.283 + long err; 10.284 + 10.285 + // Clear interrupts. 10.286 + 10.287 + _regs[I2c_int_mask] = 0; 10.288 + 10.289 + for (i = 0; i < length; i++) 10.290 + { 10.291 + // Increment the device register. 10.292 + 10.293 + _regs[I2c_register] = _device_register++; 10.294 + _regs[I2c_operation] = _segment_read ? I2c_operation_segment_read 10.295 + : I2c_operation_read; 10.296 + 10.297 + // Wait and then read. 10.298 + 10.299 + err = i2c_wait(); 10.300 + if (err) 10.301 + break; 10.302 + 10.303 + buf[i] = _regs[I2c_data_in]; 10.304 + } 10.305 + 10.306 + // Mask interrupts again. 10.307 + 10.308 + _regs[I2c_int_mask] = I2c_int_status_done | I2c_int_status_error; 10.309 + 10.310 + return i; 10.311 +} 10.312 + 10.313 +void Hdmi_jz4780_chip::i2c_set_address(uint8_t address) 10.314 +{ 10.315 + _regs[I2c_device_address] = address; 10.316 + _segment_read = false; 10.317 + i2c_set_register(0); 10.318 +} 10.319 + 10.320 +void Hdmi_jz4780_chip::i2c_set_segment(uint8_t segment) 10.321 +{ 10.322 + _regs[I2c_segment_address] = 0x30; 10.323 + _regs[I2c_segment_pointer] = segment; 10.324 + _segment_read = true; 10.325 + i2c_set_register(0); 10.326 +} 10.327 + 10.328 +void Hdmi_jz4780_chip::i2c_set_register(uint8_t device_register) 10.329 +{ 10.330 + _device_register = device_register; 10.331 +} 10.332 + 10.333 + 10.334 + 10.335 +// C language interface functions. 10.336 + 10.337 +void *jz4780_hdmi_init(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq) 10.338 +{ 10.339 + return (void *) new Hdmi_jz4780_chip(start, end, irq); 10.340 +} 10.341 + 10.342 +void jz4780_hdmi_get_version(void *hdmi, uint8_t *major, uint16_t *minor) 10.343 +{ 10.344 + static_cast<Hdmi_jz4780_chip *>(hdmi)->get_version(major, minor); 10.345 +} 10.346 + 10.347 +int jz4780_hdmi_i2c_read(void *hdmi, uint8_t *buf, unsigned int length) 10.348 +{ 10.349 + return static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_read(buf, length); 10.350 +} 10.351 + 10.352 +void jz4780_hdmi_i2c_set_address(void *hdmi, uint8_t address) 10.353 +{ 10.354 + static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_address(address); 10.355 +} 10.356 + 10.357 +void jz4780_hdmi_i2c_set_segment(void *hdmi, uint8_t segment) 10.358 +{ 10.359 + static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_segment(segment); 10.360 +} 10.361 + 10.362 +void jz4780_hdmi_i2c_set_register(void *hdmi, uint8_t device_register) 10.363 +{ 10.364 + static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_register(device_register); 10.365 +}
11.1 --- a/pkg/devices/lib/lcd/include/lcd-jz4740.h Sat Jan 25 16:07:18 2020 +0100 11.2 +++ b/pkg/devices/lib/lcd/include/lcd-jz4740.h Fri May 22 00:17:25 2020 +0200 11.3 @@ -1,7 +1,7 @@ 11.4 /* 11.5 * LCD peripheral support for the JZ4740 and related SoCs. 11.6 * 11.7 - * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk> 11.8 + * Copyright (C) 2018, 2020 Paul Boddie <paul@boddie.org.uk> 11.9 * 11.10 * This program is free software; you can redistribute it and/or 11.11 * modify it under the terms of the GNU General Public License as 11.12 @@ -38,6 +38,21 @@ 11.13 uint32_t command; /* CMD: command */ 11.14 }; 11.15 11.16 +/* 8-word "new descriptor" variant for the JZ4780. */ 11.17 + 11.18 +struct Jz4780_lcd_descriptor 11.19 +{ 11.20 + struct Jz4780_lcd_descriptor *next; /* FDADR: frame descriptor address */ 11.21 + uint32_t source; /* FSADR: frame source address */ 11.22 + uint32_t identifier; /* FIDR: frame identifier */ 11.23 + uint32_t command; /* CMD: command */ 11.24 + uint32_t offset; /* OFFSIZE: offset in words between lines */ 11.25 + uint32_t page_width; /* PW: number of words per line (16x16 block mode) */ 11.26 + uint32_t command_position; /* CNUM: command number (smart LCD mode) or 11.27 + CPOS: foreground position and properties */ 11.28 + uint32_t fg_size; /* DESSIZE: foreground size and alpha properties */ 11.29 +}; 11.30 + 11.31 11.32 11.33 /* C++ language interface. */
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/Makefile Fri May 22 00:17:25 2020 +0200 12.3 @@ -0,0 +1,8 @@ 12.4 +PKGDIR ?= .. 12.5 +L4DIR ?= $(PKGDIR)/../.. 12.6 + 12.7 +TARGET = ex_ci20_hdmi_i2c 12.8 +SRC_C = ci20_hdmi_i2c.c 12.9 +REQUIRES_LIBS = libio l4re_c-util libdevice-util libdrivers-cpm libdrivers-hdmi libdrivers-gpio libedid 12.10 + 12.11 +include $(L4DIR)/mk/prog.mk
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Fri May 22 00:17:25 2020 +0200 13.3 @@ -0,0 +1,241 @@ 13.4 +/* 13.5 + * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de> 13.6 + * economic rights: Technische Universität Dresden (Germany) 13.7 + * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk> 13.8 + * 13.9 + * This file is part of TUD:OS and distributed under the terms of the 13.10 + * GNU General Public License 2. 13.11 + * Please see the COPYING-GPL-2 file for details. 13.12 + */ 13.13 +/* 13.14 + * Access the HDMI I2C peripheral on the MIPS Creator CI20 board. 13.15 + */ 13.16 + 13.17 +#include <l4/devices/cpm-jz4780.h> 13.18 +#include <l4/devices/gpio-jz4780.h> 13.19 +#include <l4/devices/hdmi-jz4780.h> 13.20 +#include <l4/devices/memory.h> 13.21 +#include <l4/io/io.h> 13.22 +#include <l4/libedid/edid.h> 13.23 +#include <l4/re/env.h> 13.24 +#include <l4/re/c/util/cap_alloc.h> 13.25 +#include <l4/sys/factory.h> 13.26 +#include <l4/sys/icu.h> 13.27 +#include <l4/sys/ipc.h> 13.28 +#include <l4/sys/irq.h> 13.29 +#include <l4/sys/rcv_endpoint.h> 13.30 +#include <l4/vbus/vbus.h> 13.31 +#include <stdio.h> 13.32 +#include <unistd.h> 13.33 +#include <stdint.h> 13.34 +#include <string.h> 13.35 + 13.36 + 13.37 + 13.38 +enum { 13.39 + DDCSCL = 24, /* via PORTF */ 13.40 + DDCSDA = 25, /* via PORTF */ 13.41 +}; 13.42 + 13.43 + 13.44 + 13.45 +/* Device and resource discovery. */ 13.46 + 13.47 +static long item_in_range(long start, long end, long index) 13.48 +{ 13.49 + if (start < end) 13.50 + return start + index; 13.51 + else 13.52 + return start - index; 13.53 +} 13.54 + 13.55 +static void show_timings(uint8_t *buf) 13.56 +{ 13.57 + unsigned int width, height; 13.58 + 13.59 + /* Attempt to decode EDID information. */ 13.60 + 13.61 + libedid_prefered_resolution(buf, &width, &height); 13.62 + printf("Preferred resolution: %d x %d\n", width, height); 13.63 + 13.64 + libedid_dump_standard_timings(buf); 13.65 +} 13.66 + 13.67 +int main(void) 13.68 +{ 13.69 + long err; 13.70 + 13.71 + /* Buffer for EDID data. */ 13.72 + 13.73 + uint8_t edid[128]; 13.74 + unsigned int length = 0, i; 13.75 + 13.76 + /* Version details. */ 13.77 + 13.78 + uint8_t hdmi_major; 13.79 + uint16_t hdmi_minor; 13.80 + 13.81 + /* Peripheral memory. */ 13.82 + 13.83 + l4_addr_t cpm_base = 0, cpm_base_end = 0; 13.84 + l4_addr_t gpio_base = 0, gpio_base_end = 0; 13.85 + l4_addr_t hdmi_base = 0, hdmi_base_end = 0; 13.86 + l4_addr_t port_f, port_f_end; 13.87 + 13.88 + /* Peripheral abstractions. */ 13.89 + 13.90 + void *cpm; 13.91 + void *gpio_port_f; 13.92 + void *hdmi; 13.93 + 13.94 + /* Access to IRQs. */ 13.95 + 13.96 + l4_uint32_t hdmi_irq_start = 0, hdmi_irq_end = 0; 13.97 + l4_cap_idx_t icucap, irqcap; 13.98 + 13.99 + irqcap = l4re_util_cap_alloc(); 13.100 + icucap = l4re_env_get_cap("icu"); 13.101 + 13.102 + if (l4_is_invalid_cap(icucap)) 13.103 + { 13.104 + printf("No 'icu' capability available in the virtual bus.\n"); 13.105 + return 1; 13.106 + } 13.107 + 13.108 + if (l4_is_invalid_cap(irqcap)) 13.109 + { 13.110 + printf("Capabilities not available for interrupts.\n"); 13.111 + return 1; 13.112 + } 13.113 + 13.114 + /* Obtain resource details describing the interrupt for HDMI I2C. */ 13.115 + 13.116 + printf("Access IRQ...\n"); 13.117 + 13.118 + if (get_irq("jz4780-hdmi", &hdmi_irq_start, &hdmi_irq_end) < 0) 13.119 + return 1; 13.120 + 13.121 + printf("IRQ range at %d...%d.\n", hdmi_irq_start, hdmi_irq_end); 13.122 + 13.123 + /* Create interrupt objects. */ 13.124 + 13.125 + err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irqcap)); 13.126 + 13.127 + if (err) 13.128 + { 13.129 + printf("Could not create IRQ object: %lx\n", err); 13.130 + return 1; 13.131 + } 13.132 + 13.133 + /* Bind interrupt objects to IRQ numbers. Here, the first HDMI interrupt is 13.134 + bound, this being the general HDMI interrupt. */ 13.135 + 13.136 + err = l4_error(l4_icu_bind(icucap, 13.137 + item_in_range(hdmi_irq_start, hdmi_irq_end, 0), 13.138 + irqcap)); 13.139 + 13.140 + if (err) 13.141 + { 13.142 + printf("Could not bind IRQ to the ICU: %ld\n", err); 13.143 + return 1; 13.144 + } 13.145 + 13.146 + /* Attach ourselves to the interrupt handler. */ 13.147 + 13.148 + err = l4_error(l4_rcv_ep_bind_thread(irqcap, l4re_env()->main_thread, 0)); 13.149 + 13.150 + if (err) 13.151 + { 13.152 + printf("Could not attach to IRQs: %ld\n", err); 13.153 + return 1; 13.154 + } 13.155 + 13.156 + /* Obtain resource details describing I/O memory. */ 13.157 + 13.158 + printf("Access CPM...\n"); 13.159 + 13.160 + if (get_memory("jz4780-cpm", &cpm_base, &cpm_base_end) < 0) 13.161 + return 1; 13.162 + 13.163 + printf("CPM at 0x%lx...0x%lx.\n", cpm_base, cpm_base_end); 13.164 + 13.165 + printf("Access GPIO...\n"); 13.166 + 13.167 + if (get_memory("jz4780-gpio", &gpio_base, &gpio_base_end) < 0) 13.168 + return 1; 13.169 + 13.170 + printf("GPIO at 0x%lx...0x%lx.\n", gpio_base, gpio_base_end); 13.171 + 13.172 + printf("Access HDMI...\n"); 13.173 + 13.174 + if (get_memory("jz4780-hdmi", &hdmi_base, &hdmi_base_end) < 0) 13.175 + return 1; 13.176 + 13.177 + printf("HDMI at 0x%lx...0x%lx.\n", hdmi_base, hdmi_base_end); 13.178 + 13.179 + /* Obtain CPM object. */ 13.180 + 13.181 + cpm = jz4780_cpm_init(cpm_base); 13.182 + 13.183 + printf("VPLL frequency: %d\n", jz4780_cpm_get_vpll_frequency(cpm)); 13.184 + printf("HDMI divider: %d\n", jz4780_cpm_get_hdmi_divider(cpm)); 13.185 + printf("HDMI frequency: %d\n", jz4780_cpm_get_hdmi_frequency(cpm)); 13.186 + 13.187 + jz4780_cpm_stop_hdmi(cpm); 13.188 + jz4780_cpm_set_hdmi_frequency(cpm, 27000000); 13.189 + 13.190 + printf("HDMI divider: %d\n", jz4780_cpm_get_hdmi_divider(cpm)); 13.191 + printf("HDMI frequency: %d\n", jz4780_cpm_get_hdmi_frequency(cpm)); 13.192 + 13.193 + jz4780_cpm_start_hdmi(cpm); 13.194 + 13.195 + /* Configure pins. */ 13.196 + 13.197 + port_f = gpio_base + 0x500; 13.198 + port_f_end = port_f + 0x100; 13.199 + 13.200 + printf("PORTF at 0x%lx...0x%lx.\n", port_f, port_f_end); 13.201 + 13.202 + gpio_port_f = jz4780_gpio_init(port_f, port_f_end, 32, 0x7fa7f00f, 0x00580ff0); 13.203 + 13.204 + printf("Set up GPIO pins...\n"); 13.205 + 13.206 + jz4780_gpio_config_pad(gpio_port_f, DDCSCL, Function_alt, 0); 13.207 + jz4780_gpio_config_pad(gpio_port_f, DDCSDA, Function_alt, 0); 13.208 + 13.209 + /* Obtain HDMI reference. */ 13.210 + 13.211 + printf("Set up HDMI...\n"); 13.212 + 13.213 + hdmi = jz4780_hdmi_init(hdmi_base, hdmi_base_end, irqcap); 13.214 + 13.215 + printf("Read version...\n"); 13.216 + 13.217 + jz4780_hdmi_get_version(hdmi, &hdmi_major, &hdmi_minor); 13.218 + 13.219 + printf("HDMI version is %x.%03x\n", hdmi_major, hdmi_minor); 13.220 + 13.221 + printf("Read EDID...\n"); 13.222 + 13.223 + jz4780_hdmi_i2c_set_address(hdmi, 0x50); 13.224 + length = jz4780_hdmi_i2c_read(hdmi, edid, 128); 13.225 + 13.226 + if (length) 13.227 + { 13.228 + for (i = 0; i < length; i++) 13.229 + printf("%02x%c", edid[i], ((i % 16) != 15) ? ' ' : '\n'); 13.230 + } 13.231 + 13.232 + show_timings(edid); 13.233 + 13.234 + /* Detach from the interrupt. */ 13.235 + 13.236 + err = l4_error(l4_irq_detach(irqcap)); 13.237 + 13.238 + if (err) 13.239 + printf("Error detaching from IRQ: %ld\n", err); 13.240 + 13.241 + printf("Done.\n"); 13.242 + 13.243 + return 0; 13.244 +}
14.1 --- a/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Sat Jan 25 16:07:18 2020 +0100 14.2 +++ b/pkg/landfall-examples/ci20_i2c/ci20_i2c.c Fri May 22 00:17:25 2020 +0200 14.3 @@ -29,6 +29,14 @@ 14.4 #include <stdint.h> 14.5 #include <string.h> 14.6 14.7 +#define REG(x) *((volatile uint32_t *) (x)) 14.8 + 14.9 +#define RTC_RTCCR 0x00 14.10 +#define RTC_HCR 0x20 14.11 +#define RTC_HSPR 0x34 14.12 +#define RTC_WENR 0x3c 14.13 +#define RTC_PWRONCR 0x3c 14.14 + 14.15 14.16 14.17 enum { 14.18 @@ -233,6 +241,18 @@ 14.19 return i2c_set_reg(i2c_channel, 0x02, rtcregs + 2, 7, irqcap); 14.20 } 14.21 14.22 +static void rtc_write_ready(l4_addr_t rtc_base) 14.23 +{ 14.24 + while (!(REG(rtc_base + RTC_RTCCR) & 0x80)); 14.25 +} 14.26 + 14.27 +static void rtc_write_enable(l4_addr_t rtc_base) 14.28 +{ 14.29 + rtc_write_ready(rtc_base); 14.30 + REG(rtc_base + RTC_WENR) = 0xa55a; 14.31 + while (!(REG(rtc_base + RTC_WENR) & 0x80000000)); 14.32 +} 14.33 + 14.34 int main(void) 14.35 { 14.36 long err; 14.37 @@ -242,6 +262,7 @@ 14.38 l4_addr_t gpio_base = 0, gpio_base_end = 0; 14.39 l4_addr_t i2c_base = 0, i2c_base_end = 0; 14.40 l4_addr_t cpm_base = 0, cpm_base_end = 0; 14.41 + l4_addr_t rtc_base = 0, rtc_base_end = 0; 14.42 l4_addr_t port_d, port_d_end; 14.43 l4_addr_t port_e, port_e_end; 14.44 14.45 @@ -311,6 +332,13 @@ 14.46 14.47 printf("I2C at 0x%lx...0x%lx.\n", i2c_base, i2c_base_end); 14.48 14.49 + printf("Access RTC...\n"); 14.50 + 14.51 + if (get_memory("jz4780-rtc", &rtc_base, &rtc_base_end) < 0) 14.52 + return 1; 14.53 + 14.54 + printf("RTC at 0x%lx...0x%lx.\n", rtc_base, rtc_base_end); 14.55 + 14.56 /* Create interrupt objects. */ 14.57 14.58 err = l4_error(l4_factory_create_irq(l4re_global_env->factory, irq0cap)) || 14.59 @@ -406,13 +434,31 @@ 14.60 14.61 printf("Updated %d registers.\n", rtc_update(i2c4, irq4cap, rtcregs)); 14.62 14.63 - for (i = 0; i < 10; i++) 14.64 + for (i = 0; i < 3; i++) 14.65 { 14.66 rtc_dump(i2c4, irq4cap, rtcregs); 14.67 rtc_datetime(rtcregs); 14.68 sleep(1); 14.69 } 14.70 14.71 + /* Investigate the internal RTC registers. */ 14.72 + 14.73 + printf("Control: %08x\n", REG(rtc_base + RTC_RTCCR)); 14.74 + printf("Hibernate: %08x\n", REG(rtc_base + RTC_HCR)); 14.75 + printf("Scratchpad: %08x\n", REG(rtc_base + RTC_HSPR)); 14.76 + printf("Power on control: %08x\n", REG(rtc_base + RTC_PWRONCR)); 14.77 + printf("Write enable: %08x\n", REG(rtc_base + RTC_WENR)); 14.78 + 14.79 + rtc_write_enable(rtc_base); 14.80 + rtc_write_ready(rtc_base); 14.81 + REG(rtc_base + RTC_HSPR) = 0x12345678; 14.82 + 14.83 + for (i = 0; i < 3; i++) 14.84 + { 14.85 + printf("Scratchpad: %08x\n", REG(rtc_base + RTC_HSPR)); 14.86 + sleep(1); 14.87 + } 14.88 + 14.89 jz4780_i2c_disable(i2c0); 14.90 jz4780_i2c_disable(i2c4); 14.91