0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/err.h>
0010 #include <linux/io.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/slab.h>
0013 #include <linux/seq_file.h>
0014
0015 #include <video/omapfb_dss.h>
0016
0017 #include "dss.h"
0018 #include "hdmi.h"
0019
0020 struct hdmi_phy_features {
0021 bool bist_ctrl;
0022 bool ldo_voltage;
0023 unsigned long max_phy;
0024 };
0025
0026 static const struct hdmi_phy_features *phy_feat;
0027
0028 void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
0029 {
0030 #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
0031 hdmi_read_reg(phy->base, r))
0032
0033 DUMPPHY(HDMI_TXPHY_TX_CTRL);
0034 DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
0035 DUMPPHY(HDMI_TXPHY_POWER_CTRL);
0036 DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
0037 if (phy_feat->bist_ctrl)
0038 DUMPPHY(HDMI_TXPHY_BIST_CONTROL);
0039 }
0040
0041 int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes)
0042 {
0043 int i;
0044
0045 for (i = 0; i < 8; i += 2) {
0046 u8 lane, pol;
0047 int dx, dy;
0048
0049 dx = lanes[i];
0050 dy = lanes[i + 1];
0051
0052 if (dx < 0 || dx >= 8)
0053 return -EINVAL;
0054
0055 if (dy < 0 || dy >= 8)
0056 return -EINVAL;
0057
0058 if (dx & 1) {
0059 if (dy != dx - 1)
0060 return -EINVAL;
0061 pol = 1;
0062 } else {
0063 if (dy != dx + 1)
0064 return -EINVAL;
0065 pol = 0;
0066 }
0067
0068 lane = dx / 2;
0069
0070 phy->lane_function[lane] = i / 2;
0071 phy->lane_polarity[lane] = pol;
0072 }
0073
0074 return 0;
0075 }
0076
0077 static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
0078 {
0079 static const u16 pad_cfg_list[] = {
0080 0x0123,
0081 0x0132,
0082 0x0312,
0083 0x0321,
0084 0x0231,
0085 0x0213,
0086 0x1023,
0087 0x1032,
0088 0x3012,
0089 0x3021,
0090 0x2031,
0091 0x2013,
0092 0x1203,
0093 0x1302,
0094 0x3102,
0095 0x3201,
0096 0x2301,
0097 0x2103,
0098 0x1230,
0099 0x1320,
0100 0x3120,
0101 0x3210,
0102 0x2310,
0103 0x2130,
0104 };
0105
0106 u16 lane_cfg = 0;
0107 int i;
0108 unsigned lane_cfg_val;
0109 u16 pol_val = 0;
0110
0111 for (i = 0; i < 4; ++i)
0112 lane_cfg |= phy->lane_function[i] << ((3 - i) * 4);
0113
0114 pol_val |= phy->lane_polarity[0] << 0;
0115 pol_val |= phy->lane_polarity[1] << 3;
0116 pol_val |= phy->lane_polarity[2] << 2;
0117 pol_val |= phy->lane_polarity[3] << 1;
0118
0119 for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i)
0120 if (pad_cfg_list[i] == lane_cfg)
0121 break;
0122
0123 if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list)))
0124 i = 0;
0125
0126 lane_cfg_val = i;
0127
0128 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22);
0129 REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
0130 }
0131
0132 int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
0133 unsigned long lfbitclk)
0134 {
0135 u8 freqout;
0136
0137
0138
0139
0140
0141 hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
0142
0143
0144
0145
0146
0147 if (phy_feat->bist_ctrl)
0148 REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
0149
0150
0151
0152
0153
0154 if (hfbitclk != lfbitclk)
0155 freqout = 0;
0156 else if (hfbitclk / 10 < phy_feat->max_phy)
0157 freqout = 1;
0158 else
0159 freqout = 2;
0160
0161
0162
0163
0164
0165 REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
0166
0167
0168 hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
0169
0170
0171 if (phy_feat->ldo_voltage)
0172 REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
0173
0174 hdmi_phy_configure_lanes(phy);
0175
0176 return 0;
0177 }
0178
0179 static const struct hdmi_phy_features omap44xx_phy_feats = {
0180 .bist_ctrl = false,
0181 .ldo_voltage = true,
0182 .max_phy = 185675000,
0183 };
0184
0185 static const struct hdmi_phy_features omap54xx_phy_feats = {
0186 .bist_ctrl = true,
0187 .ldo_voltage = false,
0188 .max_phy = 186000000,
0189 };
0190
0191 static const struct hdmi_phy_features *hdmi_phy_get_features(void)
0192 {
0193 switch (omapdss_get_version()) {
0194 case OMAPDSS_VER_OMAP4430_ES1:
0195 case OMAPDSS_VER_OMAP4430_ES2:
0196 case OMAPDSS_VER_OMAP4:
0197 return &omap44xx_phy_feats;
0198
0199 case OMAPDSS_VER_OMAP5:
0200 case OMAPDSS_VER_DRA7xx:
0201 return &omap54xx_phy_feats;
0202
0203 default:
0204 return NULL;
0205 }
0206 }
0207
0208 int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
0209 {
0210 phy_feat = hdmi_phy_get_features();
0211 if (!phy_feat)
0212 return -ENODEV;
0213
0214 phy->base = devm_platform_ioremap_resource_byname(pdev, "phy");
0215 if (IS_ERR(phy->base)) {
0216 DSSERR("can't ioremap TX PHY\n");
0217 return PTR_ERR(phy->base);
0218 }
0219
0220 return 0;
0221 }