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