Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HDMI PHY
0004  *
0005  * Copyright (C) 2013 Texas Instruments Incorporated
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      * Read address 0 in order to get the SCP reset done completed
0139      * Dummy access performed to make sure reset is done
0140      */
0141     hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
0142 
0143     /*
0144      * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
0145      * HDMI_PHYPWRCMD_LDOON command.
0146      */
0147     if (phy_feat->bist_ctrl)
0148         REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
0149 
0150     /*
0151      * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
0152      * to be used for TMDS.
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      * Write to phy address 0 to configure the clock
0163      * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
0164      */
0165     REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
0166 
0167     /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
0168     hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
0169 
0170     /* Setup max LDO voltage */
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 }