1 /* 2 * HDMI PHY 3 * 4 * Copyright (C) 2013 Texas Instruments Incorporated 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published by 8 * the Free Software Foundation. 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/err.h> 13 #include <linux/io.h> 14 #include <linux/platform_device.h> 15 #include <linux/slab.h> 16 #include <linux/seq_file.h> 17 18 #include <video/omapfb_dss.h> 19 20 #include "dss.h" 21 #include "hdmi.h" 22 23 struct hdmi_phy_features { 24 bool bist_ctrl; 25 bool ldo_voltage; 26 unsigned long max_phy; 27 }; 28 29 static const struct hdmi_phy_features *phy_feat; 30 31 void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s) 32 { 33 #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ 34 hdmi_read_reg(phy->base, r)) 35 36 DUMPPHY(HDMI_TXPHY_TX_CTRL); 37 DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); 38 DUMPPHY(HDMI_TXPHY_POWER_CTRL); 39 DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); 40 if (phy_feat->bist_ctrl) 41 DUMPPHY(HDMI_TXPHY_BIST_CONTROL); 42 } 43 44 int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes) 45 { 46 int i; 47 48 for (i = 0; i < 8; i += 2) { 49 u8 lane, pol; 50 int dx, dy; 51 52 dx = lanes[i]; 53 dy = lanes[i + 1]; 54 55 if (dx < 0 || dx >= 8) 56 return -EINVAL; 57 58 if (dy < 0 || dy >= 8) 59 return -EINVAL; 60 61 if (dx & 1) { 62 if (dy != dx - 1) 63 return -EINVAL; 64 pol = 1; 65 } else { 66 if (dy != dx + 1) 67 return -EINVAL; 68 pol = 0; 69 } 70 71 lane = dx / 2; 72 73 phy->lane_function[lane] = i / 2; 74 phy->lane_polarity[lane] = pol; 75 } 76 77 return 0; 78 } 79 80 static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) 81 { 82 static const u16 pad_cfg_list[] = { 83 0x0123, 84 0x0132, 85 0x0312, 86 0x0321, 87 0x0231, 88 0x0213, 89 0x1023, 90 0x1032, 91 0x3012, 92 0x3021, 93 0x2031, 94 0x2013, 95 0x1203, 96 0x1302, 97 0x3102, 98 0x3201, 99 0x2301, 100 0x2103, 101 0x1230, 102 0x1320, 103 0x3120, 104 0x3210, 105 0x2310, 106 0x2130, 107 }; 108 109 u16 lane_cfg = 0; 110 int i; 111 unsigned lane_cfg_val; 112 u16 pol_val = 0; 113 114 for (i = 0; i < 4; ++i) 115 lane_cfg |= phy->lane_function[i] << ((3 - i) * 4); 116 117 pol_val |= phy->lane_polarity[0] << 0; 118 pol_val |= phy->lane_polarity[1] << 3; 119 pol_val |= phy->lane_polarity[2] << 2; 120 pol_val |= phy->lane_polarity[3] << 1; 121 122 for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i) 123 if (pad_cfg_list[i] == lane_cfg) 124 break; 125 126 if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list))) 127 i = 0; 128 129 lane_cfg_val = i; 130 131 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22); 132 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); 133 } 134 135 int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk, 136 unsigned long lfbitclk) 137 { 138 u8 freqout; 139 140 /* 141 * Read address 0 in order to get the SCP reset done completed 142 * Dummy access performed to make sure reset is done 143 */ 144 hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL); 145 146 /* 147 * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the 148 * HDMI_PHYPWRCMD_LDOON command. 149 */ 150 if (phy_feat->bist_ctrl) 151 REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); 152 153 /* 154 * If the hfbitclk != lfbitclk, it means the lfbitclk was configured 155 * to be used for TMDS. 156 */ 157 if (hfbitclk != lfbitclk) 158 freqout = 0; 159 else if (hfbitclk / 10 < phy_feat->max_phy) 160 freqout = 1; 161 else 162 freqout = 2; 163 164 /* 165 * Write to phy address 0 to configure the clock 166 * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field 167 */ 168 REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30); 169 170 /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ 171 hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); 172 173 /* Setup max LDO voltage */ 174 if (phy_feat->ldo_voltage) 175 REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); 176 177 hdmi_phy_configure_lanes(phy); 178 179 return 0; 180 } 181 182 static const struct hdmi_phy_features omap44xx_phy_feats = { 183 .bist_ctrl = false, 184 .ldo_voltage = true, 185 .max_phy = 185675000, 186 }; 187 188 static const struct hdmi_phy_features omap54xx_phy_feats = { 189 .bist_ctrl = true, 190 .ldo_voltage = false, 191 .max_phy = 186000000, 192 }; 193 194 static const struct hdmi_phy_features *hdmi_phy_get_features(void) 195 { 196 switch (omapdss_get_version()) { 197 case OMAPDSS_VER_OMAP4430_ES1: 198 case OMAPDSS_VER_OMAP4430_ES2: 199 case OMAPDSS_VER_OMAP4: 200 return &omap44xx_phy_feats; 201 202 case OMAPDSS_VER_OMAP5: 203 case OMAPDSS_VER_DRA7xx: 204 return &omap54xx_phy_feats; 205 206 default: 207 return NULL; 208 } 209 } 210 211 int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy) 212 { 213 struct resource *res; 214 215 phy_feat = hdmi_phy_get_features(); 216 if (!phy_feat) 217 return -ENODEV; 218 219 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy"); 220 if (!res) { 221 DSSERR("can't get PHY mem resource\n"); 222 return -EINVAL; 223 } 224 225 phy->base = devm_ioremap_resource(&pdev->dev, res); 226 if (IS_ERR(phy->base)) { 227 DSSERR("can't ioremap TX PHY\n"); 228 return PTR_ERR(phy->base); 229 } 230 231 return 0; 232 } 233