root/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun8i_hdmi_phy_config_a83t
  2. sun8i_hdmi_phy_config_h3
  3. sun8i_hdmi_phy_config
  4. sun8i_hdmi_phy_disable_a83t
  5. sun8i_hdmi_phy_disable_h3
  6. sun8i_hdmi_phy_disable
  7. sun8i_hdmi_phy_unlock
  8. sun50i_hdmi_phy_init_h6
  9. sun8i_hdmi_phy_init_a83t
  10. sun8i_hdmi_phy_init_h3
  11. sun8i_hdmi_phy_init
  12. sun8i_hdmi_phy_set_ops
  13. sun8i_hdmi_phy_probe
  14. sun8i_hdmi_phy_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
   4  */
   5 
   6 #include <linux/delay.h>
   7 #include <linux/of_address.h>
   8 
   9 #include "sun8i_dw_hdmi.h"
  10 
  11 /*
  12  * Address can be actually any value. Here is set to same value as
  13  * it is set in BSP driver.
  14  */
  15 #define I2C_ADDR        0x69
  16 
  17 static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
  18         {
  19                 30666000, {
  20                         { 0x00b3, 0x0000 },
  21                         { 0x2153, 0x0000 },
  22                         { 0x40f3, 0x0000 },
  23                 },
  24         },  {
  25                 36800000, {
  26                         { 0x00b3, 0x0000 },
  27                         { 0x2153, 0x0000 },
  28                         { 0x40a2, 0x0001 },
  29                 },
  30         },  {
  31                 46000000, {
  32                         { 0x00b3, 0x0000 },
  33                         { 0x2142, 0x0001 },
  34                         { 0x40a2, 0x0001 },
  35                 },
  36         },  {
  37                 61333000, {
  38                         { 0x0072, 0x0001 },
  39                         { 0x2142, 0x0001 },
  40                         { 0x40a2, 0x0001 },
  41                 },
  42         },  {
  43                 73600000, {
  44                         { 0x0072, 0x0001 },
  45                         { 0x2142, 0x0001 },
  46                         { 0x4061, 0x0002 },
  47                 },
  48         },  {
  49                 92000000, {
  50                         { 0x0072, 0x0001 },
  51                         { 0x2145, 0x0002 },
  52                         { 0x4061, 0x0002 },
  53                 },
  54         },  {
  55                 122666000, {
  56                         { 0x0051, 0x0002 },
  57                         { 0x2145, 0x0002 },
  58                         { 0x4061, 0x0002 },
  59                 },
  60         },  {
  61                 147200000, {
  62                         { 0x0051, 0x0002 },
  63                         { 0x2145, 0x0002 },
  64                         { 0x4064, 0x0003 },
  65                 },
  66         },  {
  67                 184000000, {
  68                         { 0x0051, 0x0002 },
  69                         { 0x214c, 0x0003 },
  70                         { 0x4064, 0x0003 },
  71                 },
  72         },  {
  73                 226666000, {
  74                         { 0x0040, 0x0003 },
  75                         { 0x214c, 0x0003 },
  76                         { 0x4064, 0x0003 },
  77                 },
  78         },  {
  79                 272000000, {
  80                         { 0x0040, 0x0003 },
  81                         { 0x214c, 0x0003 },
  82                         { 0x5a64, 0x0003 },
  83                 },
  84         },  {
  85                 340000000, {
  86                         { 0x0040, 0x0003 },
  87                         { 0x3b4c, 0x0003 },
  88                         { 0x5a64, 0x0003 },
  89                 },
  90         },  {
  91                 594000000, {
  92                         { 0x1a40, 0x0003 },
  93                         { 0x3b4c, 0x0003 },
  94                         { 0x5a64, 0x0003 },
  95                 },
  96         }, {
  97                 ~0UL, {
  98                         { 0x0000, 0x0000 },
  99                         { 0x0000, 0x0000 },
 100                         { 0x0000, 0x0000 },
 101                 },
 102         }
 103 };
 104 
 105 static const struct dw_hdmi_curr_ctrl sun50i_h6_cur_ctr[] = {
 106         /* pixelclk    bpp8    bpp10   bpp12 */
 107         { 25175000,  { 0x0000, 0x0000, 0x0000 }, },
 108         { 27000000,  { 0x0012, 0x0000, 0x0000 }, },
 109         { 59400000,  { 0x0008, 0x0008, 0x0008 }, },
 110         { 72000000,  { 0x0008, 0x0008, 0x001b }, },
 111         { 74250000,  { 0x0013, 0x0013, 0x0013 }, },
 112         { 90000000,  { 0x0008, 0x001a, 0x001b }, },
 113         { 118800000, { 0x001b, 0x001a, 0x001b }, },
 114         { 144000000, { 0x001b, 0x001a, 0x0034 }, },
 115         { 180000000, { 0x001b, 0x0033, 0x0034 }, },
 116         { 216000000, { 0x0036, 0x0033, 0x0034 }, },
 117         { 237600000, { 0x0036, 0x0033, 0x001b }, },
 118         { 288000000, { 0x0036, 0x001b, 0x001b }, },
 119         { 297000000, { 0x0019, 0x001b, 0x0019 }, },
 120         { 330000000, { 0x0036, 0x001b, 0x001b }, },
 121         { 594000000, { 0x003f, 0x001b, 0x001b }, },
 122         { ~0UL,      { 0x0000, 0x0000, 0x0000 }, }
 123 };
 124 
 125 static const struct dw_hdmi_phy_config sun50i_h6_phy_config[] = {
 126         /*pixelclk   symbol   term   vlev*/
 127         { 74250000,  0x8009, 0x0004, 0x0232},
 128         { 148500000, 0x8029, 0x0004, 0x0273},
 129         { 594000000, 0x8039, 0x0004, 0x014a},
 130         { ~0UL,      0x0000, 0x0000, 0x0000}
 131 };
 132 
 133 static int sun8i_hdmi_phy_config_a83t(struct dw_hdmi *hdmi,
 134                                       struct sun8i_hdmi_phy *phy,
 135                                       unsigned int clk_rate)
 136 {
 137         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
 138                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
 139                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
 140 
 141         /* power down */
 142         dw_hdmi_phy_gen2_txpwron(hdmi, 0);
 143         dw_hdmi_phy_gen2_pddq(hdmi, 1);
 144 
 145         dw_hdmi_phy_reset(hdmi);
 146 
 147         dw_hdmi_phy_gen2_pddq(hdmi, 0);
 148 
 149         dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
 150 
 151         /*
 152          * Values are taken from BSP HDMI driver. Although AW didn't
 153          * release any documentation, explanation of this values can
 154          * be found in i.MX 6Dual/6Quad Reference Manual.
 155          */
 156         if (clk_rate <= 27000000) {
 157                 dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
 158                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
 159                 dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
 160                 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
 161                 dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
 162                 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
 163         } else if (clk_rate <= 74250000) {
 164                 dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
 165                 dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
 166                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
 167                 dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
 168                 dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
 169                 dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
 170         } else if (clk_rate <= 148500000) {
 171                 dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
 172                 dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
 173                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
 174                 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
 175                 dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
 176                 dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
 177         } else {
 178                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
 179                 dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
 180                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
 181                 dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
 182                 dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
 183                 dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
 184         }
 185 
 186         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
 187         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
 188         dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
 189 
 190         dw_hdmi_phy_gen2_txpwron(hdmi, 1);
 191 
 192         return 0;
 193 }
 194 
 195 static int sun8i_hdmi_phy_config_h3(struct dw_hdmi *hdmi,
 196                                     struct sun8i_hdmi_phy *phy,
 197                                     unsigned int clk_rate)
 198 {
 199         u32 pll_cfg1_init;
 200         u32 pll_cfg2_init;
 201         u32 ana_cfg1_end;
 202         u32 ana_cfg2_init;
 203         u32 ana_cfg3_init;
 204         u32 b_offset = 0;
 205         u32 val;
 206 
 207         /* bandwidth / frequency independent settings */
 208 
 209         pll_cfg1_init = SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN |
 210                         SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN |
 211                         SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(7) |
 212                         SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(1) |
 213                         SUN8I_HDMI_PHY_PLL_CFG1_PLLDBEN |
 214                         SUN8I_HDMI_PHY_PLL_CFG1_CS |
 215                         SUN8I_HDMI_PHY_PLL_CFG1_CP_S(2) |
 216                         SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63) |
 217                         SUN8I_HDMI_PHY_PLL_CFG1_BWS;
 218 
 219         pll_cfg2_init = SUN8I_HDMI_PHY_PLL_CFG2_SV_H |
 220                         SUN8I_HDMI_PHY_PLL_CFG2_VCOGAIN_EN |
 221                         SUN8I_HDMI_PHY_PLL_CFG2_SDIV2;
 222 
 223         ana_cfg1_end = SUN8I_HDMI_PHY_ANA_CFG1_REG_SVBH(1) |
 224                        SUN8I_HDMI_PHY_ANA_CFG1_AMP_OPT |
 225                        SUN8I_HDMI_PHY_ANA_CFG1_EMP_OPT |
 226                        SUN8I_HDMI_PHY_ANA_CFG1_AMPCK_OPT |
 227                        SUN8I_HDMI_PHY_ANA_CFG1_EMPCK_OPT |
 228                        SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL |
 229                        SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG |
 230                        SUN8I_HDMI_PHY_ANA_CFG1_REG_SCKTMDS |
 231                        SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN |
 232                        SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK |
 233                        SUN8I_HDMI_PHY_ANA_CFG1_TXEN_ALL |
 234                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK |
 235                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
 236                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
 237                        SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
 238                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2 |
 239                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
 240                        SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
 241                        SUN8I_HDMI_PHY_ANA_CFG1_CKEN |
 242                        SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
 243                        SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
 244                        SUN8I_HDMI_PHY_ANA_CFG1_ENBI;
 245 
 246         ana_cfg2_init = SUN8I_HDMI_PHY_ANA_CFG2_M_EN |
 247                         SUN8I_HDMI_PHY_ANA_CFG2_REG_DENCK |
 248                         SUN8I_HDMI_PHY_ANA_CFG2_REG_DEN |
 249                         SUN8I_HDMI_PHY_ANA_CFG2_REG_CKSS(1) |
 250                         SUN8I_HDMI_PHY_ANA_CFG2_REG_CSMPS(1);
 251 
 252         ana_cfg3_init = SUN8I_HDMI_PHY_ANA_CFG3_REG_WIRE(0x3e0) |
 253                         SUN8I_HDMI_PHY_ANA_CFG3_SDAEN |
 254                         SUN8I_HDMI_PHY_ANA_CFG3_SCLEN;
 255 
 256         /* bandwidth / frequency dependent settings */
 257         if (clk_rate <= 27000000) {
 258                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
 259                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
 260                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
 261                                  SUN8I_HDMI_PHY_PLL_CFG2_S(4);
 262                 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
 263                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
 264                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
 265                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(3) |
 266                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(5);
 267         } else if (clk_rate <= 74250000) {
 268                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
 269                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
 270                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
 271                                  SUN8I_HDMI_PHY_PLL_CFG2_S(5);
 272                 ana_cfg1_end |= SUN8I_HDMI_PHY_ANA_CFG1_REG_CALSW;
 273                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4) |
 274                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_RESDI(phy->rcal);
 275                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(5) |
 276                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(7);
 277         } else if (clk_rate <= 148500000) {
 278                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 |
 279                                  SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(32);
 280                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(4) |
 281                                  SUN8I_HDMI_PHY_PLL_CFG2_S(6);
 282                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
 283                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
 284                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(2);
 285                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(7) |
 286                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(9);
 287         } else {
 288                 b_offset = 2;
 289                 pll_cfg1_init |= SUN8I_HDMI_PHY_PLL_CFG1_CNT_INT(63);
 290                 pll_cfg2_init |= SUN8I_HDMI_PHY_PLL_CFG2_VCO_S(6) |
 291                                  SUN8I_HDMI_PHY_PLL_CFG2_S(7);
 292                 ana_cfg2_init |= SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSWCK |
 293                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_BIGSW |
 294                                  SUN8I_HDMI_PHY_ANA_CFG2_REG_SLV(4);
 295                 ana_cfg3_init |= SUN8I_HDMI_PHY_ANA_CFG3_REG_AMPCK(9) |
 296                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_AMP(13) |
 297                                  SUN8I_HDMI_PHY_ANA_CFG3_REG_EMP(3);
 298         }
 299 
 300         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 301                            SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);
 302 
 303         /*
 304          * NOTE: We have to be careful not to overwrite PHY parent
 305          * clock selection bit and clock divider.
 306          */
 307         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
 308                            (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
 309                            pll_cfg1_init);
 310         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,
 311                            (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
 312                            pll_cfg2_init);
 313         usleep_range(10000, 15000);
 314         regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG3_REG,
 315                      SUN8I_HDMI_PHY_PLL_CFG3_SOUT_DIV2);
 316         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
 317                            SUN8I_HDMI_PHY_PLL_CFG1_PLLEN,
 318                            SUN8I_HDMI_PHY_PLL_CFG1_PLLEN);
 319         msleep(100);
 320 
 321         /* get B value */
 322         regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
 323         val = (val & SUN8I_HDMI_PHY_ANA_STS_B_OUT_MSK) >>
 324                 SUN8I_HDMI_PHY_ANA_STS_B_OUT_SHIFT;
 325         val = min(val + b_offset, (u32)0x3f);
 326 
 327         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
 328                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
 329                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD,
 330                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD1 |
 331                            SUN8I_HDMI_PHY_PLL_CFG1_REG_OD);
 332         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
 333                            SUN8I_HDMI_PHY_PLL_CFG1_B_IN_MSK,
 334                            val << SUN8I_HDMI_PHY_PLL_CFG1_B_IN_SHIFT);
 335         msleep(100);
 336         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, ana_cfg1_end);
 337         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG2_REG, ana_cfg2_init);
 338         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG, ana_cfg3_init);
 339 
 340         return 0;
 341 }
 342 
 343 static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
 344                                  struct drm_display_mode *mode)
 345 {
 346         struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
 347         u32 val = 0;
 348 
 349         if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 350                 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NHSYNC;
 351 
 352         if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 353                 val |= SUN8I_HDMI_PHY_DBG_CTRL_POL_NVSYNC;
 354 
 355         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
 356                            SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);
 357 
 358         if (phy->variant->has_phy_clk)
 359                 clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000);
 360 
 361         return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);
 362 };
 363 
 364 static void sun8i_hdmi_phy_disable_a83t(struct dw_hdmi *hdmi,
 365                                         struct sun8i_hdmi_phy *phy)
 366 {
 367         dw_hdmi_phy_gen2_txpwron(hdmi, 0);
 368         dw_hdmi_phy_gen2_pddq(hdmi, 1);
 369 
 370         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
 371                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
 372 }
 373 
 374 static void sun8i_hdmi_phy_disable_h3(struct dw_hdmi *hdmi,
 375                                       struct sun8i_hdmi_phy *phy)
 376 {
 377         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 378                      SUN8I_HDMI_PHY_ANA_CFG1_LDOEN |
 379                      SUN8I_HDMI_PHY_ANA_CFG1_ENVBS |
 380                      SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
 381         regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, 0);
 382 }
 383 
 384 static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
 385 {
 386         struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
 387 
 388         phy->variant->phy_disable(hdmi, phy);
 389 }
 390 
 391 static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
 392         .init = &sun8i_hdmi_phy_config,
 393         .disable = &sun8i_hdmi_phy_disable,
 394         .read_hpd = &dw_hdmi_phy_read_hpd,
 395         .update_hpd = &dw_hdmi_phy_update_hpd,
 396         .setup_hpd = &dw_hdmi_phy_setup_hpd,
 397 };
 398 
 399 static void sun8i_hdmi_phy_unlock(struct sun8i_hdmi_phy *phy)
 400 {
 401         /* enable read access to HDMI controller */
 402         regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
 403                      SUN8I_HDMI_PHY_READ_EN_MAGIC);
 404 
 405         /* unscramble register offsets */
 406         regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
 407                      SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
 408 }
 409 
 410 static void sun50i_hdmi_phy_init_h6(struct sun8i_hdmi_phy *phy)
 411 {
 412         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
 413                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
 414                            SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
 415 
 416         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
 417                            0xffff0000, 0x80c00000);
 418 }
 419 
 420 static void sun8i_hdmi_phy_init_a83t(struct sun8i_hdmi_phy *phy)
 421 {
 422         sun8i_hdmi_phy_unlock(phy);
 423 
 424         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
 425                            SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
 426                            SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
 427 
 428         /*
 429          * Set PHY I2C address. It must match to the address set by
 430          * dw_hdmi_phy_set_slave_addr().
 431          */
 432         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
 433                            SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
 434                            SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
 435 }
 436 
 437 static void sun8i_hdmi_phy_init_h3(struct sun8i_hdmi_phy *phy)
 438 {
 439         unsigned int val;
 440 
 441         sun8i_hdmi_phy_unlock(phy);
 442 
 443         regmap_write(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG, 0);
 444         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 445                            SUN8I_HDMI_PHY_ANA_CFG1_ENBI,
 446                            SUN8I_HDMI_PHY_ANA_CFG1_ENBI);
 447         udelay(5);
 448         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 449                            SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN,
 450                            SUN8I_HDMI_PHY_ANA_CFG1_TMDSCLK_EN);
 451         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 452                            SUN8I_HDMI_PHY_ANA_CFG1_ENVBS,
 453                            SUN8I_HDMI_PHY_ANA_CFG1_ENVBS);
 454         usleep_range(10, 20);
 455         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 456                            SUN8I_HDMI_PHY_ANA_CFG1_LDOEN,
 457                            SUN8I_HDMI_PHY_ANA_CFG1_LDOEN);
 458         udelay(5);
 459         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 460                            SUN8I_HDMI_PHY_ANA_CFG1_CKEN,
 461                            SUN8I_HDMI_PHY_ANA_CFG1_CKEN);
 462         usleep_range(40, 100);
 463         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 464                            SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL,
 465                            SUN8I_HDMI_PHY_ANA_CFG1_ENRCAL);
 466         usleep_range(100, 200);
 467         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 468                            SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG,
 469                            SUN8I_HDMI_PHY_ANA_CFG1_ENCALOG);
 470         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 471                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
 472                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
 473                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2,
 474                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS0 |
 475                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS1 |
 476                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDS2);
 477 
 478         /* wait for calibration to finish */
 479         regmap_read_poll_timeout(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, val,
 480                                  (val & SUN8I_HDMI_PHY_ANA_STS_RCALEND2D),
 481                                  100, 2000);
 482 
 483         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 484                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK,
 485                            SUN8I_HDMI_PHY_ANA_CFG1_ENP2S_TMDSCLK);
 486         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,
 487                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
 488                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
 489                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
 490                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK,
 491                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS0 |
 492                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS1 |
 493                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDS2 |
 494                            SUN8I_HDMI_PHY_ANA_CFG1_BIASEN_TMDSCLK);
 495 
 496         /* enable DDC communication */
 497         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG3_REG,
 498                            SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
 499                            SUN8I_HDMI_PHY_ANA_CFG3_SDAEN,
 500                            SUN8I_HDMI_PHY_ANA_CFG3_SCLEN |
 501                            SUN8I_HDMI_PHY_ANA_CFG3_SDAEN);
 502 
 503         /* reset PHY PLL clock parent */
 504         regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
 505                            SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK, 0);
 506 
 507         /* set HW control of CEC pins */
 508         regmap_write(phy->regs, SUN8I_HDMI_PHY_CEC_REG, 0);
 509 
 510         /* read calibration data */
 511         regmap_read(phy->regs, SUN8I_HDMI_PHY_ANA_STS_REG, &val);
 512         phy->rcal = (val & SUN8I_HDMI_PHY_ANA_STS_RCAL_MASK) >> 2;
 513 }
 514 
 515 void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
 516 {
 517         phy->variant->phy_init(phy);
 518 }
 519 
 520 void sun8i_hdmi_phy_set_ops(struct sun8i_hdmi_phy *phy,
 521                             struct dw_hdmi_plat_data *plat_data)
 522 {
 523         struct sun8i_hdmi_phy_variant *variant = phy->variant;
 524 
 525         if (variant->is_custom_phy) {
 526                 plat_data->phy_ops = &sun8i_hdmi_phy_ops;
 527                 plat_data->phy_name = "sun8i_dw_hdmi_phy";
 528                 plat_data->phy_data = phy;
 529         } else {
 530                 plat_data->mpll_cfg = variant->mpll_cfg;
 531                 plat_data->cur_ctr = variant->cur_ctr;
 532                 plat_data->phy_config = variant->phy_cfg;
 533         }
 534 }
 535 
 536 static struct regmap_config sun8i_hdmi_phy_regmap_config = {
 537         .reg_bits       = 32,
 538         .val_bits       = 32,
 539         .reg_stride     = 4,
 540         .max_register   = SUN8I_HDMI_PHY_CEC_REG,
 541         .name           = "phy"
 542 };
 543 
 544 static const struct sun8i_hdmi_phy_variant sun8i_a83t_hdmi_phy = {
 545         .is_custom_phy = true,
 546         .phy_init = &sun8i_hdmi_phy_init_a83t,
 547         .phy_disable = &sun8i_hdmi_phy_disable_a83t,
 548         .phy_config = &sun8i_hdmi_phy_config_a83t,
 549 };
 550 
 551 static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {
 552         .has_phy_clk = true,
 553         .is_custom_phy = true,
 554         .phy_init = &sun8i_hdmi_phy_init_h3,
 555         .phy_disable = &sun8i_hdmi_phy_disable_h3,
 556         .phy_config = &sun8i_hdmi_phy_config_h3,
 557 };
 558 
 559 static const struct sun8i_hdmi_phy_variant sun8i_r40_hdmi_phy = {
 560         .has_phy_clk = true,
 561         .has_second_pll = true,
 562         .is_custom_phy = true,
 563         .phy_init = &sun8i_hdmi_phy_init_h3,
 564         .phy_disable = &sun8i_hdmi_phy_disable_h3,
 565         .phy_config = &sun8i_hdmi_phy_config_h3,
 566 };
 567 
 568 static const struct sun8i_hdmi_phy_variant sun50i_a64_hdmi_phy = {
 569         .has_phy_clk = true,
 570         .is_custom_phy = true,
 571         .phy_init = &sun8i_hdmi_phy_init_h3,
 572         .phy_disable = &sun8i_hdmi_phy_disable_h3,
 573         .phy_config = &sun8i_hdmi_phy_config_h3,
 574 };
 575 
 576 static const struct sun8i_hdmi_phy_variant sun50i_h6_hdmi_phy = {
 577         .cur_ctr  = sun50i_h6_cur_ctr,
 578         .mpll_cfg = sun50i_h6_mpll_cfg,
 579         .phy_cfg  = sun50i_h6_phy_config,
 580         .phy_init = &sun50i_hdmi_phy_init_h6,
 581 };
 582 
 583 static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
 584         {
 585                 .compatible = "allwinner,sun8i-a83t-hdmi-phy",
 586                 .data = &sun8i_a83t_hdmi_phy,
 587         },
 588         {
 589                 .compatible = "allwinner,sun8i-h3-hdmi-phy",
 590                 .data = &sun8i_h3_hdmi_phy,
 591         },
 592         {
 593                 .compatible = "allwinner,sun8i-r40-hdmi-phy",
 594                 .data = &sun8i_r40_hdmi_phy,
 595         },
 596         {
 597                 .compatible = "allwinner,sun50i-a64-hdmi-phy",
 598                 .data = &sun50i_a64_hdmi_phy,
 599         },
 600         {
 601                 .compatible = "allwinner,sun50i-h6-hdmi-phy",
 602                 .data = &sun50i_h6_hdmi_phy,
 603         },
 604         { /* sentinel */ }
 605 };
 606 
 607 int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
 608 {
 609         const struct of_device_id *match;
 610         struct device *dev = hdmi->dev;
 611         struct sun8i_hdmi_phy *phy;
 612         struct resource res;
 613         void __iomem *regs;
 614         int ret;
 615 
 616         match = of_match_node(sun8i_hdmi_phy_of_table, node);
 617         if (!match) {
 618                 dev_err(dev, "Incompatible HDMI PHY\n");
 619                 return -EINVAL;
 620         }
 621 
 622         phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
 623         if (!phy)
 624                 return -ENOMEM;
 625 
 626         phy->variant = (struct sun8i_hdmi_phy_variant *)match->data;
 627 
 628         ret = of_address_to_resource(node, 0, &res);
 629         if (ret) {
 630                 dev_err(dev, "phy: Couldn't get our resources\n");
 631                 return ret;
 632         }
 633 
 634         regs = devm_ioremap_resource(dev, &res);
 635         if (IS_ERR(regs)) {
 636                 dev_err(dev, "Couldn't map the HDMI PHY registers\n");
 637                 return PTR_ERR(regs);
 638         }
 639 
 640         phy->regs = devm_regmap_init_mmio(dev, regs,
 641                                           &sun8i_hdmi_phy_regmap_config);
 642         if (IS_ERR(phy->regs)) {
 643                 dev_err(dev, "Couldn't create the HDMI PHY regmap\n");
 644                 return PTR_ERR(phy->regs);
 645         }
 646 
 647         phy->clk_bus = of_clk_get_by_name(node, "bus");
 648         if (IS_ERR(phy->clk_bus)) {
 649                 dev_err(dev, "Could not get bus clock\n");
 650                 return PTR_ERR(phy->clk_bus);
 651         }
 652 
 653         phy->clk_mod = of_clk_get_by_name(node, "mod");
 654         if (IS_ERR(phy->clk_mod)) {
 655                 dev_err(dev, "Could not get mod clock\n");
 656                 ret = PTR_ERR(phy->clk_mod);
 657                 goto err_put_clk_bus;
 658         }
 659 
 660         if (phy->variant->has_phy_clk) {
 661                 phy->clk_pll0 = of_clk_get_by_name(node, "pll-0");
 662                 if (IS_ERR(phy->clk_pll0)) {
 663                         dev_err(dev, "Could not get pll-0 clock\n");
 664                         ret = PTR_ERR(phy->clk_pll0);
 665                         goto err_put_clk_mod;
 666                 }
 667 
 668                 if (phy->variant->has_second_pll) {
 669                         phy->clk_pll1 = of_clk_get_by_name(node, "pll-1");
 670                         if (IS_ERR(phy->clk_pll1)) {
 671                                 dev_err(dev, "Could not get pll-1 clock\n");
 672                                 ret = PTR_ERR(phy->clk_pll1);
 673                                 goto err_put_clk_pll0;
 674                         }
 675                 }
 676         }
 677 
 678         phy->rst_phy = of_reset_control_get_shared(node, "phy");
 679         if (IS_ERR(phy->rst_phy)) {
 680                 dev_err(dev, "Could not get phy reset control\n");
 681                 ret = PTR_ERR(phy->rst_phy);
 682                 goto err_put_clk_pll1;
 683         }
 684 
 685         ret = reset_control_deassert(phy->rst_phy);
 686         if (ret) {
 687                 dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
 688                 goto err_put_rst_phy;
 689         }
 690 
 691         ret = clk_prepare_enable(phy->clk_bus);
 692         if (ret) {
 693                 dev_err(dev, "Cannot enable bus clock: %d\n", ret);
 694                 goto err_deassert_rst_phy;
 695         }
 696 
 697         ret = clk_prepare_enable(phy->clk_mod);
 698         if (ret) {
 699                 dev_err(dev, "Cannot enable mod clock: %d\n", ret);
 700                 goto err_disable_clk_bus;
 701         }
 702 
 703         if (phy->variant->has_phy_clk) {
 704                 ret = sun8i_phy_clk_create(phy, dev,
 705                                            phy->variant->has_second_pll);
 706                 if (ret) {
 707                         dev_err(dev, "Couldn't create the PHY clock\n");
 708                         goto err_disable_clk_mod;
 709                 }
 710 
 711                 clk_prepare_enable(phy->clk_phy);
 712         }
 713 
 714         hdmi->phy = phy;
 715 
 716         return 0;
 717 
 718 err_disable_clk_mod:
 719         clk_disable_unprepare(phy->clk_mod);
 720 err_disable_clk_bus:
 721         clk_disable_unprepare(phy->clk_bus);
 722 err_deassert_rst_phy:
 723         reset_control_assert(phy->rst_phy);
 724 err_put_rst_phy:
 725         reset_control_put(phy->rst_phy);
 726 err_put_clk_pll1:
 727         clk_put(phy->clk_pll1);
 728 err_put_clk_pll0:
 729         clk_put(phy->clk_pll0);
 730 err_put_clk_mod:
 731         clk_put(phy->clk_mod);
 732 err_put_clk_bus:
 733         clk_put(phy->clk_bus);
 734 
 735         return ret;
 736 }
 737 
 738 void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
 739 {
 740         struct sun8i_hdmi_phy *phy = hdmi->phy;
 741 
 742         clk_disable_unprepare(phy->clk_mod);
 743         clk_disable_unprepare(phy->clk_bus);
 744         clk_disable_unprepare(phy->clk_phy);
 745 
 746         reset_control_assert(phy->rst_phy);
 747 
 748         reset_control_put(phy->rst_phy);
 749 
 750         clk_put(phy->clk_pll0);
 751         clk_put(phy->clk_pll1);
 752         clk_put(phy->clk_mod);
 753         clk_put(phy->clk_bus);
 754 }

/* [<][>][^][v][top][bottom][index][help] */