paul@62 | 1 | /* |
paul@62 | 2 | * JZ4780 HDMI peripheral support. |
paul@62 | 3 | * |
paul@62 | 4 | * Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk> |
paul@62 | 5 | * |
paul@66 | 6 | * Some structures have been adopted from the Linux DRM bridge driver for |
paul@66 | 7 | * Synopsys DW-HDMI with the following attribution: |
paul@66 | 8 | * |
paul@66 | 9 | * Copyright (C) 2011 Freescale Semiconductor, Inc. |
paul@66 | 10 | * |
paul@62 | 11 | * This program is free software; you can redistribute it and/or |
paul@62 | 12 | * modify it under the terms of the GNU General Public License as |
paul@62 | 13 | * published by the Free Software Foundation; either version 2 of |
paul@62 | 14 | * the License, or (at your option) any later version. |
paul@62 | 15 | * |
paul@62 | 16 | * This program is distributed in the hope that it will be useful, |
paul@62 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
paul@62 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
paul@62 | 19 | * GNU General Public License for more details. |
paul@62 | 20 | * |
paul@62 | 21 | * You should have received a copy of the GNU General Public License |
paul@62 | 22 | * along with this program; if not, write to the Free Software |
paul@62 | 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, |
paul@62 | 24 | * Boston, MA 02110-1301, USA |
paul@62 | 25 | */ |
paul@62 | 26 | |
paul@62 | 27 | #pragma once |
paul@62 | 28 | |
paul@66 | 29 | #include <l4/devices/lcd-jz4740-panel.h> |
paul@62 | 30 | #include <l4/sys/types.h> |
paul@62 | 31 | #include <stdint.h> |
paul@62 | 32 | |
paul@62 | 33 | |
paul@62 | 34 | |
paul@66 | 35 | // PHY capability definition type. |
paul@66 | 36 | |
paul@66 | 37 | struct Phy_capabilities |
paul@66 | 38 | { |
paul@66 | 39 | uint8_t type; |
paul@66 | 40 | const char *name; |
paul@66 | 41 | int gen; |
paul@66 | 42 | int svsret; |
paul@66 | 43 | int configure; |
paul@66 | 44 | }; |
paul@66 | 45 | |
paul@66 | 46 | |
paul@66 | 47 | |
paul@66 | 48 | // PHY configuration types. |
paul@66 | 49 | |
paul@66 | 50 | enum Phy_resolutions |
paul@66 | 51 | { |
paul@66 | 52 | Phy_resolution_8bpc = 0, |
paul@66 | 53 | Phy_resolution_10bpc = 1, |
paul@66 | 54 | Phy_resolution_12bpc = 2, |
paul@66 | 55 | Phy_resolution_count = 3, |
paul@66 | 56 | }; |
paul@66 | 57 | |
paul@66 | 58 | struct Phy_mpll_config |
paul@66 | 59 | { |
paul@66 | 60 | unsigned long pixelclock; // frequency (Hz) |
paul@66 | 61 | struct { |
paul@66 | 62 | uint16_t cpce; |
paul@66 | 63 | uint16_t gmp; |
paul@66 | 64 | } res[Phy_resolution_count]; |
paul@66 | 65 | }; |
paul@66 | 66 | |
paul@66 | 67 | struct Phy_curr_ctrl |
paul@66 | 68 | { |
paul@66 | 69 | unsigned long pixelclock; // frequency (Hz) |
paul@66 | 70 | uint16_t curr[Phy_resolution_count]; |
paul@66 | 71 | }; |
paul@66 | 72 | |
paul@66 | 73 | struct Phy_config |
paul@66 | 74 | { |
paul@66 | 75 | unsigned long pixelclock; // frequency (Hz) |
paul@66 | 76 | uint16_t symbol; // clock symbol and transmitter control |
paul@66 | 77 | uint16_t term; // transmission termination value |
paul@66 | 78 | uint16_t vlevel; // voltage level control |
paul@66 | 79 | }; |
paul@66 | 80 | |
paul@66 | 81 | |
paul@66 | 82 | |
paul@62 | 83 | #ifdef __cplusplus |
paul@62 | 84 | |
paul@62 | 85 | #include <l4/devices/hw_mmio_register_block.h> |
paul@62 | 86 | |
paul@62 | 87 | // HDMI device control. |
paul@62 | 88 | |
paul@62 | 89 | class Hdmi_jz4780_chip |
paul@62 | 90 | { |
paul@62 | 91 | private: |
paul@62 | 92 | l4_addr_t _start, _end; |
paul@62 | 93 | l4_cap_idx_t _irq; |
paul@62 | 94 | Hw::Register_block<8> _regs; |
paul@62 | 95 | |
paul@62 | 96 | // Identification. |
paul@62 | 97 | |
paul@62 | 98 | uint16_t _version; |
paul@66 | 99 | uint8_t _phy_type; |
paul@66 | 100 | const struct Phy_capabilities *_phy_def; |
paul@66 | 101 | |
paul@66 | 102 | // Input/output properties. |
paul@66 | 103 | |
paul@66 | 104 | struct Jz4740_lcd_panel *_panel; |
paul@66 | 105 | unsigned long _pixelclock; |
paul@62 | 106 | |
paul@62 | 107 | // Transfer properties. |
paul@62 | 108 | |
paul@62 | 109 | bool _segment_read; |
paul@66 | 110 | uint8_t _device_register, _phy_device_register; |
paul@66 | 111 | |
paul@66 | 112 | // Convenience methods for register access. |
paul@66 | 113 | |
paul@66 | 114 | void reg_update(uint32_t reg, uint32_t bits, bool enable); |
paul@66 | 115 | void reg_update_field(uint32_t reg, uint32_t mask, uint32_t bits); |
paul@66 | 116 | void reg_fill_field(uint32_t reg, uint32_t mask); |
paul@62 | 117 | |
paul@62 | 118 | protected: |
paul@66 | 119 | unsigned long get_pixelclock(); |
paul@66 | 120 | |
paul@62 | 121 | void get_identification(); |
paul@62 | 122 | |
paul@65 | 123 | void irq_init(); |
paul@62 | 124 | |
paul@66 | 125 | void i2c_init(uint32_t reset, uint32_t divider, uint32_t config0, |
paul@66 | 126 | uint32_t config1, uint32_t status, uint32_t mask); |
paul@62 | 127 | |
paul@66 | 128 | long i2c_wait(uint32_t status); |
paul@66 | 129 | |
paul@66 | 130 | void phy_irq_init(); |
paul@65 | 131 | |
paul@62 | 132 | public: |
paul@66 | 133 | Hdmi_jz4780_chip(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq, |
paul@66 | 134 | struct Jz4740_lcd_panel *panel); |
paul@66 | 135 | |
paul@66 | 136 | // Chipset querying. |
paul@62 | 137 | |
paul@62 | 138 | void get_version(uint8_t *major, uint16_t *minor); |
paul@66 | 139 | void get_phy_capabilities(const struct Phy_capabilities **phy_def); |
paul@66 | 140 | |
paul@66 | 141 | // I2C operations. |
paul@62 | 142 | |
paul@62 | 143 | int i2c_read(uint8_t *buf, unsigned int length); |
paul@66 | 144 | |
paul@62 | 145 | void i2c_set_address(uint8_t address); |
paul@62 | 146 | void i2c_set_segment(uint8_t segment); |
paul@62 | 147 | void i2c_set_register(uint8_t device_register); |
paul@65 | 148 | |
paul@66 | 149 | int i2c_phy_write(uint8_t address, uint16_t value); |
paul@66 | 150 | int i2c_phy_write(uint16_t *buf, unsigned int length); |
paul@66 | 151 | |
paul@66 | 152 | void i2c_phy_set_address(uint8_t address); |
paul@66 | 153 | void i2c_phy_set_register(uint8_t device_register); |
paul@66 | 154 | |
paul@66 | 155 | // PHY configuration operations. |
paul@66 | 156 | |
paul@66 | 157 | void phy_enable_powerdown(bool enable); |
paul@66 | 158 | void phy_enable_tmds(bool enable); |
paul@66 | 159 | void phy_enable_svsret(bool enable); |
paul@66 | 160 | void phy_enable_gen2_powerdown(bool enable); |
paul@66 | 161 | void phy_enable_gen2_tx_power(bool enable); |
paul@66 | 162 | void phy_enable_interface(bool enable); |
paul@66 | 163 | |
paul@66 | 164 | // PHY operations. |
paul@66 | 165 | |
paul@66 | 166 | long phy_configure(); |
paul@66 | 167 | long phy_configure_specific(); |
paul@66 | 168 | long phy_init(); |
paul@66 | 169 | void phy_power_off(); |
paul@66 | 170 | void phy_power_on(); |
paul@66 | 171 | void phy_reset(); |
paul@66 | 172 | |
paul@66 | 173 | // Hotplug and signalling support. |
paul@66 | 174 | |
paul@65 | 175 | bool connected(); |
paul@65 | 176 | long wait_for_connection(); |
paul@66 | 177 | long wait_for_tx_phy_lock(int level); |
paul@66 | 178 | long wait_for_phy_irq(uint32_t int_status_flags, uint32_t status_flags, |
paul@66 | 179 | uint32_t polarity_flags); |
paul@66 | 180 | |
paul@66 | 181 | // Video output initialisation. |
paul@66 | 182 | |
paul@66 | 183 | void enable_overflow_irq(bool enable); |
paul@66 | 184 | void frame_init(); |
paul@66 | 185 | void data_path_init(); |
paul@66 | 186 | void packet_init(); |
paul@66 | 187 | void csc_init(); |
paul@66 | 188 | void sample_init(); |
paul@66 | 189 | void hdcp_init(); |
paul@66 | 190 | |
paul@66 | 191 | // Enable the video output. |
paul@66 | 192 | |
paul@66 | 193 | long enable(unsigned long pixelclock); |
paul@62 | 194 | }; |
paul@62 | 195 | |
paul@62 | 196 | #endif /* __cplusplus */ |
paul@62 | 197 | |
paul@62 | 198 | |
paul@62 | 199 | |
paul@62 | 200 | /* C language interface. */ |
paul@62 | 201 | |
paul@62 | 202 | EXTERN_C_BEGIN |
paul@62 | 203 | |
paul@66 | 204 | void *jz4780_hdmi_init(l4_addr_t start, l4_addr_t end, l4_cap_idx_t irq, |
paul@66 | 205 | struct Jz4740_lcd_panel *panel); |
paul@62 | 206 | |
paul@62 | 207 | void jz4780_hdmi_get_version(void *hdmi, uint8_t *major, uint16_t *minor); |
paul@62 | 208 | |
paul@66 | 209 | void jz4780_hdmi_get_phy_capabilities(void *hdmi, const struct Phy_capabilities **phy_def); |
paul@66 | 210 | |
paul@62 | 211 | int jz4780_hdmi_i2c_read(void *hdmi, uint8_t *buf, unsigned int length); |
paul@62 | 212 | |
paul@62 | 213 | void jz4780_hdmi_i2c_set_address(void *hdmi, uint8_t address); |
paul@62 | 214 | |
paul@62 | 215 | void jz4780_hdmi_i2c_set_segment(void *hdmi, uint8_t segment); |
paul@62 | 216 | |
paul@62 | 217 | void jz4780_hdmi_i2c_set_register(void *hdmi, uint8_t device_register); |
paul@62 | 218 | |
paul@66 | 219 | int jz4780_hdmi_phy_i2c_write(void *hdmi, uint16_t *buf, unsigned int length); |
paul@66 | 220 | |
paul@66 | 221 | void jz4780_hdmi_i2c_phy_set_address(void *hdmi, uint8_t address); |
paul@66 | 222 | |
paul@66 | 223 | void jz4780_hdmi_i2c_phy_set_register(void *hdmi, uint8_t device_register); |
paul@66 | 224 | |
paul@65 | 225 | int jz4780_hdmi_connected(void *hdmi); |
paul@65 | 226 | |
paul@65 | 227 | long jz4780_hdmi_wait_for_connection(void *hdmi); |
paul@65 | 228 | |
paul@66 | 229 | long jz4780_hdmi_enable(void *hdmi, unsigned long pixelclock); |
paul@66 | 230 | |
paul@62 | 231 | EXTERN_C_END |