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 - https://www.ti.com/
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      * Read address 0 in order to get the SCP reset done completed
0130      * Dummy access performed to make sure reset is done
0131      */
0132     hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
0133 
0134     /*
0135      * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
0136      * HDMI_PHYPWRCMD_LDOON command.
0137     */
0138     if (phy->features->bist_ctrl)
0139         REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
0140 
0141     /*
0142      * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
0143      * to be used for TMDS.
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      * Write to phy address 0 to configure the clock
0154      * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
0155      */
0156     REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
0157 
0158     /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
0159     hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
0160 
0161     /* Setup max LDO voltage */
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 }