2.1 --- a/pkg/devices/lib/hdmi/src/jz4780.cc Sat May 23 16:05:22 2020 +0200
2.2 +++ b/pkg/devices/lib/hdmi/src/jz4780.cc Sat May 23 22:34:17 2020 +0200
2.3 @@ -96,17 +96,28 @@
2.4
2.5 I2c_phy_int_config0 = 0x3027, // PHY_I2CM_INT_ADDR
2.6 I2c_phy_int_config1 = 0x3028, // PHY_I2CM_CTLINT_ADDR
2.7 +
2.8 + // PHY registers.
2.9 +
2.10 + Phy_config = 0x3000, // PHY_CONF0
2.11 + Phy_test0 = 0x3001, // PHY_TST0
2.12 + Phy_test1 = 0x3002, // PHY_TST1
2.13 + Phy_test2 = 0x3003, // PHY_TST2
2.14 + Phy_status = 0x3004, // PHY_STAT0
2.15 + Phy_int_config = 0x3005, // PHY_INT0
2.16 + Phy_mask = 0x3006, // PHY_MASK0
2.17 + Phy_polarity = 0x3007, // PHY_POL0
2.18 };
2.19
2.20 // Identification values.
2.21
2.22 enum Product_id_values : unsigned
2.23 {
2.24 - Product_id0_transmitter = 0xa0, // PRODUCT_ID0_HDMI_TX
2.25 + Product_id0_transmitter = 0xa0, // PRODUCT_ID0_HDMI_TX
2.26
2.27 - Product_id1_hdcp = 0xc0, // PRODUCT_ID1_HDCP
2.28 - Product_id1_receiver = 0x02, // PRODUCT_ID1_HDMI_RX
2.29 - Product_id1_transmitter = 0x01, // PRODUCT_ID1_HDMI_TX
2.30 + Product_id1_hdcp = 0xc0, // PRODUCT_ID1_HDCP
2.31 + Product_id1_receiver = 0x02, // PRODUCT_ID1_HDMI_RX
2.32 + Product_id1_transmitter = 0x01, // PRODUCT_ID1_HDMI_TX
2.33 };
2.34
2.35 // Configuration values.
2.36 @@ -134,39 +145,86 @@
2.37
2.38 enum Int_mask_bits : unsigned
2.39 {
2.40 - Int_mask_wakeup = 0x2,
2.41 - Int_mask_all = 0x1,
2.42 + Int_mask_wakeup = 0x02,
2.43 + Int_mask_all = 0x01,
2.44 };
2.45
2.46 enum I2c_int_status_bits : unsigned
2.47 {
2.48 - I2c_int_status_done = 0x2,
2.49 - I2c_int_status_error = 0x1,
2.50 + I2c_int_status_done = 0x02,
2.51 + I2c_int_status_error = 0x01,
2.52 };
2.53
2.54 // I2C operation bits.
2.55
2.56 enum I2c_operation_bits : unsigned
2.57 {
2.58 - I2c_operation_write = 0x10,
2.59 - I2c_operation_segment_read = 0x2,
2.60 - I2c_operation_read = 0x1,
2.61 + I2c_operation_write = 0x10,
2.62 + I2c_operation_segment_read = 0x02,
2.63 + I2c_operation_read = 0x01,
2.64 };
2.65
2.66 // Interrupt configuration bits.
2.67
2.68 enum I2c_int_config0_bits : unsigned
2.69 {
2.70 - I2c_int_config_done_polarity = 0x8,
2.71 - I2c_int_config_done_mask = 0x4,
2.72 + I2c_int_config0_done_polarity = 0x08,
2.73 + I2c_int_config0_done_mask = 0x04,
2.74 };
2.75
2.76 enum I2c_int_config1_bits : unsigned
2.77 {
2.78 - I2c_int_config_nack_polarity = 0x80,
2.79 - I2c_int_config_nack_mask = 0x40,
2.80 - I2c_int_config_arb_polarity = 0x8,
2.81 - I2c_int_config_arb_mask = 0x4,
2.82 + I2c_int_config1_nack_polarity = 0x80,
2.83 + I2c_int_config1_nack_mask = 0x40,
2.84 + I2c_int_config1_arb_polarity = 0x08,
2.85 + I2c_int_config1_arb_mask = 0x04,
2.86 +};
2.87 +
2.88 +// PHY configuration values.
2.89 +
2.90 +enum Phy_config_bits : unsigned
2.91 +{
2.92 + Phy_config_pdz_mask = 0x80, // PHY_CONF0_PDZ_MASK
2.93 + Phy_config_enable_tmds_mask = 0x40, // PHY_CONF0_ENTMDS_MASK
2.94 + Phy_config_svsret_mask = 0x20, // PHY_CONF0_SVSRET_MASK
2.95 + Phy_config_gen2_pddq_mask = 0x10, // PHY_CONF0_GEN2_PDDQ_MASK
2.96 + Phy_config_gen2_tx_power_on_mask = 0x08, // PHY_CONF0_GEN2_TXPWRON_MASK
2.97 + Phy_config_gen2_enable_hotplug_detect_rx_sense_mask = 0x04, // PHY_CONF0_GEN2_ENHPDRXSENSE_MASK
2.98 + Phy_config_select_data_enable_polarity_mask = 0x02, // PHY_CONF0_SELDATAENPOL_MASK
2.99 + Phy_config_select_interface_control_mask = 0x01, // PHY_CONF0_SELDIPIF_MASK
2.100 +};
2.101 +
2.102 +enum Phy_test_bits : unsigned
2.103 +{
2.104 + Phy_test0_clear_mask = 0x20, // PHY_TST0_TSTCLR_MASK
2.105 + Phy_test0_enable_mask = 0x10, // PHY_TST0_TSTEN_MASK
2.106 + Phy_test0_clock_mask = 0x01, // PHY_TST0_TSTCLK_MASK
2.107 +};
2.108 +
2.109 +// PHY status and mask values.
2.110 +
2.111 +enum Phy_status_bits : unsigned
2.112 +{
2.113 + Phy_status_rx_sense_all = 0xf0,
2.114 + Phy_status_rx_sense3 = 0x80, // PHY_RX_SENSE3
2.115 + Phy_status_rx_sense2 = 0x40, // PHY_RX_SENSE2
2.116 + Phy_status_rx_sense1 = 0x20, // PHY_RX_SENSE1
2.117 + Phy_status_rx_sense0 = 0x10, // PHY_RX_SENSE0
2.118 + Phy_status_hotplug_detect = 0x02, // PHY_HPD
2.119 + Phy_status_tx_phy_lock = 0x01, // PHY_TX_PHY_LOCK
2.120 +};
2.121 +
2.122 +// PHY interrupt status and mask bits.
2.123 +
2.124 +enum Phy_int_status_bits : unsigned
2.125 +{
2.126 + Phy_int_status_rx_sense_all = 0x3c,
2.127 + Phy_int_status_rx_sense3 = 0x20, // IH_PHY_STAT0_RX_SENSE3
2.128 + Phy_int_status_rx_sense2 = 0x10, // IH_PHY_STAT0_RX_SENSE2
2.129 + Phy_int_status_rx_sense1 = 0x08, // IH_PHY_STAT0_RX_SENSE1
2.130 + Phy_int_status_rx_sense0 = 0x04, // IH_PHY_STAT0_RX_SENSE0
2.131 + Phy_int_status_tx_phy_lock = 0x02, // IH_PHY_STAT0_TX_PHY_LOCK
2.132 + Phy_int_status_hotplug_detect = 0x01, // IH_PHY_STAT0_HPD
2.133 };
2.134
2.135
2.136 @@ -185,8 +243,9 @@
2.137 _device_register = 0;
2.138
2.139 get_identification();
2.140 - int_init();
2.141 + irq_init();
2.142 i2c_init();
2.143 + hotplug_init();
2.144 }
2.145
2.146 void Hdmi_jz4780_chip::get_identification()
2.147 @@ -200,7 +259,7 @@
2.148 *minor = _version & 0xfff;
2.149 }
2.150
2.151 -void Hdmi_jz4780_chip::int_init()
2.152 +void Hdmi_jz4780_chip::irq_init()
2.153 {
2.154 // Disable interrupts.
2.155
2.156 @@ -226,11 +285,11 @@
2.157
2.158 void Hdmi_jz4780_chip::i2c_init()
2.159 {
2.160 - // Set PHY interrupt priorities.
2.161 + // Set PHY interrupt polarities.
2.162
2.163 - _regs[I2c_phy_int_config0] = I2c_int_config_done_polarity;
2.164 - _regs[I2c_phy_int_config1] = I2c_int_config_nack_polarity |
2.165 - I2c_int_config_arb_polarity;
2.166 + _regs[I2c_phy_int_config0] = I2c_int_config0_done_polarity;
2.167 + _regs[I2c_phy_int_config1] = I2c_int_config1_nack_polarity |
2.168 + I2c_int_config1_arb_polarity;
2.169
2.170 // Software reset.
2.171
2.172 @@ -242,9 +301,9 @@
2.173
2.174 // Set interrupt polarities.
2.175
2.176 - _regs[I2c_int_config0] = I2c_int_config_done_polarity;
2.177 - _regs[I2c_int_config1] = I2c_int_config_nack_polarity |
2.178 - I2c_int_config_arb_polarity;
2.179 + _regs[I2c_int_config0] = I2c_int_config0_done_polarity;
2.180 + _regs[I2c_int_config1] = I2c_int_config1_nack_polarity |
2.181 + I2c_int_config1_arb_polarity;
2.182
2.183 // Clear and mask/mute interrupts.
2.184
2.185 @@ -255,21 +314,29 @@
2.186 long Hdmi_jz4780_chip::i2c_wait()
2.187 {
2.188 long err;
2.189 + uint8_t int_status;
2.190 + l4_msgtag_t tag;
2.191
2.192 - // Wait for around 1s.
2.193 + do
2.194 + {
2.195 + tag = l4_irq_receive(_irq, L4_IPC_NEVER);
2.196
2.197 - l4_msgtag_t tag = l4_irq_receive(_irq, L4_IPC_NEVER);
2.198 + err = l4_ipc_error(tag, l4_utcb());
2.199 + if (err)
2.200 + return err;
2.201
2.202 - err = l4_ipc_error(tag, l4_utcb());
2.203 - if (err)
2.204 - return err;
2.205 + int_status = _regs[I2c_int_status];
2.206 +
2.207 + // Test for an error condition.
2.208
2.209 - // Test for an error condition.
2.210 + if (int_status & I2c_int_status_error)
2.211 + return -L4_EIO;
2.212
2.213 - if (_regs[I2c_int_status] & I2c_int_status_error)
2.214 - return -L4_EIO;
2.215 + // Acknowledge the interrupt.
2.216
2.217 - _regs[I2c_int_status] = _regs[I2c_int_status] | I2c_int_status_done;
2.218 + _regs[I2c_int_status] = int_status;
2.219 +
2.220 + } while (!(int_status & I2c_int_status_done));
2.221
2.222 return L4_EOK;
2.223 }
2.224 @@ -279,7 +346,7 @@
2.225 unsigned int i;
2.226 long err;
2.227
2.228 - // Clear interrupts.
2.229 + // Unmask interrupts.
2.230
2.231 _regs[I2c_int_mask] = 0;
2.232
2.233 @@ -327,6 +394,61 @@
2.234 _device_register = device_register;
2.235 }
2.236
2.237 +void Hdmi_jz4780_chip::hotplug_init()
2.238 +{
2.239 + // Set PHY interrupt polarities.
2.240 +
2.241 + _regs[Phy_polarity] = Phy_status_hotplug_detect | Phy_status_rx_sense_all;
2.242 +
2.243 + // Enable/unmask second-level interrupts.
2.244 +
2.245 + _regs[Phy_mask] = _regs[Phy_mask] & ~(Phy_status_hotplug_detect | Phy_status_rx_sense_all);
2.246 +
2.247 + // Clear pending interrupts.
2.248 +
2.249 + _regs[Phy_int_status] = Phy_int_status_hotplug_detect | Phy_int_status_rx_sense_all;
2.250 +
2.251 + // Enable/unmask interrupts.
2.252 +
2.253 + _regs[Phy_int_mask] = _regs[Phy_int_mask] & ~(Phy_int_status_hotplug_detect | Phy_int_status_rx_sense_all);
2.254 +}
2.255 +
2.256 +bool Hdmi_jz4780_chip::connected()
2.257 +{
2.258 + return (_regs[Phy_status] & Phy_status_hotplug_detect) != 0;
2.259 +}
2.260 +
2.261 +long Hdmi_jz4780_chip::wait_for_connection()
2.262 +{
2.263 + long err;
2.264 + uint8_t int_status, polarity;
2.265 + l4_msgtag_t tag;
2.266 +
2.267 + do
2.268 + {
2.269 + tag = l4_irq_receive(_irq, L4_IPC_NEVER);
2.270 +
2.271 + err = l4_ipc_error(tag, l4_utcb());
2.272 + if (err)
2.273 + return err;
2.274 +
2.275 + // Obtain the details.
2.276 +
2.277 + int_status = _regs[Phy_int_status];
2.278 + polarity = _regs[Phy_polarity];
2.279 +
2.280 + // Acknowledge the interrupt.
2.281 +
2.282 + _regs[Phy_int_status] = int_status;
2.283 +
2.284 + // Continue without a hotplug event indicating connection.
2.285 +
2.286 + } while (!((int_status & Phy_int_status_hotplug_detect) &&
2.287 + (polarity & Phy_status_hotplug_detect)));
2.288 +
2.289 + return L4_EOK;
2.290 +}
2.291 +
2.292
2.293
2.294 // C language interface functions.
2.295 @@ -360,3 +482,13 @@
2.296 {
2.297 static_cast<Hdmi_jz4780_chip *>(hdmi)->i2c_set_register(device_register);
2.298 }
2.299 +
2.300 +int jz4780_hdmi_connected(void *hdmi)
2.301 +{
2.302 + return (int) static_cast<Hdmi_jz4780_chip *>(hdmi)->connected();
2.303 +}
2.304 +
2.305 +long jz4780_hdmi_wait_for_connection(void *hdmi)
2.306 +{
2.307 + return static_cast<Hdmi_jz4780_chip *>(hdmi)->wait_for_connection();
2.308 +}
3.1 --- a/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Sat May 23 16:05:22 2020 +0200
3.2 +++ b/pkg/landfall-examples/ci20_hdmi_i2c/ci20_hdmi_i2c.c Sat May 23 22:34:17 2020 +0200
3.3 @@ -1,14 +1,22 @@
3.4 -/*
3.5 - * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>
3.6 - * economic rights: Technische Universität Dresden (Germany)
3.7 - * Copyright (C) 2017, 2018, 2019, 2020 Paul Boddie <paul@boddie.org.uk>
3.8 - *
3.9 - * This file is part of TUD:OS and distributed under the terms of the
3.10 - * GNU General Public License 2.
3.11 - * Please see the COPYING-GPL-2 file for details.
3.12 - */
3.13 /*
3.14 * Access the HDMI I2C peripheral on the MIPS Creator CI20 board.
3.15 + *
3.16 + * Copyright (C) 2020 Paul Boddie <paul@boddie.org.uk>
3.17 + *
3.18 + * This program is free software; you can redistribute it and/or
3.19 + * modify it under the terms of the GNU General Public License as
3.20 + * published by the Free Software Foundation; either version 2 of
3.21 + * the License, or (at your option) any later version.
3.22 + *
3.23 + * This program is distributed in the hope that it will be useful,
3.24 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.25 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.26 + * GNU General Public License for more details.
3.27 + *
3.28 + * You should have received a copy of the GNU General Public License
3.29 + * along with this program; if not, write to the Free Software
3.30 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
3.31 + * Boston, MA 02110-1301, USA
3.32 */
3.33
3.34 #include <l4/devices/cpm-jz4780.h>
3.35 @@ -265,6 +273,11 @@
3.36
3.37 printf("HDMI version is %x.%03x\n", hdmi_major, hdmi_minor);
3.38
3.39 + printf("Connected: %s\n", jz4780_hdmi_connected(hdmi) ? "yes" : "no");
3.40 +
3.41 + while (!jz4780_hdmi_connected(hdmi))
3.42 + jz4780_hdmi_wait_for_connection(hdmi);
3.43 +
3.44 printf("Read EDID...\n");
3.45
3.46 jz4780_hdmi_i2c_set_address(hdmi, 0x50);