1 /* 2 * Copyright (C) 2013 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 * more details. 13 * 14 * You should have received a copy of the GNU General Public License along with 15 * this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "hdmi.h" 19 20 struct hdmi_phy_8x60 { 21 struct hdmi_phy base; 22 struct hdmi *hdmi; 23 }; 24 #define to_hdmi_phy_8x60(x) container_of(x, struct hdmi_phy_8x60, base) 25 26 static void hdmi_phy_8x60_destroy(struct hdmi_phy *phy) 27 { 28 struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); 29 kfree(phy_8x60); 30 } 31 32 static void hdmi_phy_8x60_reset(struct hdmi_phy *phy) 33 { 34 struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); 35 struct hdmi *hdmi = phy_8x60->hdmi; 36 unsigned int val; 37 38 val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); 39 40 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 41 /* pull low */ 42 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 43 val & ~HDMI_PHY_CTRL_SW_RESET); 44 } else { 45 /* pull high */ 46 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 47 val | HDMI_PHY_CTRL_SW_RESET); 48 } 49 50 msleep(100); 51 52 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 53 /* pull high */ 54 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 55 val | HDMI_PHY_CTRL_SW_RESET); 56 } else { 57 /* pull low */ 58 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 59 val & ~HDMI_PHY_CTRL_SW_RESET); 60 } 61 } 62 63 static void hdmi_phy_8x60_powerup(struct hdmi_phy *phy, 64 unsigned long int pixclock) 65 { 66 struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); 67 struct hdmi *hdmi = phy_8x60->hdmi; 68 69 /* De-serializer delay D/C for non-lbk mode: */ 70 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG0, 71 HDMI_8x60_PHY_REG0_DESER_DEL_CTRL(3)); 72 73 if (pixclock == 27000000) { 74 /* video_format == HDMI_VFRMT_720x480p60_16_9 */ 75 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1, 76 HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | 77 HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(3)); 78 } else { 79 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG1, 80 HDMI_8x60_PHY_REG1_DTEST_MUX_SEL(5) | 81 HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(4)); 82 } 83 84 /* No matter what, start from the power down mode: */ 85 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 86 HDMI_8x60_PHY_REG2_PD_PWRGEN | 87 HDMI_8x60_PHY_REG2_PD_PLL | 88 HDMI_8x60_PHY_REG2_PD_DRIVE_4 | 89 HDMI_8x60_PHY_REG2_PD_DRIVE_3 | 90 HDMI_8x60_PHY_REG2_PD_DRIVE_2 | 91 HDMI_8x60_PHY_REG2_PD_DRIVE_1 | 92 HDMI_8x60_PHY_REG2_PD_DESER); 93 94 /* Turn PowerGen on: */ 95 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 96 HDMI_8x60_PHY_REG2_PD_PLL | 97 HDMI_8x60_PHY_REG2_PD_DRIVE_4 | 98 HDMI_8x60_PHY_REG2_PD_DRIVE_3 | 99 HDMI_8x60_PHY_REG2_PD_DRIVE_2 | 100 HDMI_8x60_PHY_REG2_PD_DRIVE_1 | 101 HDMI_8x60_PHY_REG2_PD_DESER); 102 103 /* Turn PLL power on: */ 104 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 105 HDMI_8x60_PHY_REG2_PD_DRIVE_4 | 106 HDMI_8x60_PHY_REG2_PD_DRIVE_3 | 107 HDMI_8x60_PHY_REG2_PD_DRIVE_2 | 108 HDMI_8x60_PHY_REG2_PD_DRIVE_1 | 109 HDMI_8x60_PHY_REG2_PD_DESER); 110 111 /* Write to HIGH after PLL power down de-assert: */ 112 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3, 113 HDMI_8x60_PHY_REG3_PLL_ENABLE); 114 115 /* ASIC power on; PHY REG9 = 0 */ 116 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0); 117 118 /* Enable PLL lock detect, PLL lock det will go high after lock 119 * Enable the re-time logic 120 */ 121 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12, 122 HDMI_8x60_PHY_REG12_RETIMING_EN | 123 HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN); 124 125 /* Drivers are on: */ 126 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 127 HDMI_8x60_PHY_REG2_PD_DESER); 128 129 /* If the RX detector is needed: */ 130 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 131 HDMI_8x60_PHY_REG2_RCV_SENSE_EN | 132 HDMI_8x60_PHY_REG2_PD_DESER); 133 134 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG4, 0); 135 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG5, 0); 136 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG6, 0); 137 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG7, 0); 138 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG8, 0); 139 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG9, 0); 140 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG10, 0); 141 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG11, 0); 142 143 /* If we want to use lock enable based on counting: */ 144 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG12, 145 HDMI_8x60_PHY_REG12_RETIMING_EN | 146 HDMI_8x60_PHY_REG12_PLL_LOCK_DETECT_EN | 147 HDMI_8x60_PHY_REG12_FORCE_LOCK); 148 } 149 150 static void hdmi_phy_8x60_powerdown(struct hdmi_phy *phy) 151 { 152 struct hdmi_phy_8x60 *phy_8x60 = to_hdmi_phy_8x60(phy); 153 struct hdmi *hdmi = phy_8x60->hdmi; 154 155 /* Assert RESET PHY from controller */ 156 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 157 HDMI_PHY_CTRL_SW_RESET); 158 udelay(10); 159 /* De-assert RESET PHY from controller */ 160 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 0); 161 /* Turn off Driver */ 162 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 163 HDMI_8x60_PHY_REG2_PD_DRIVE_4 | 164 HDMI_8x60_PHY_REG2_PD_DRIVE_3 | 165 HDMI_8x60_PHY_REG2_PD_DRIVE_2 | 166 HDMI_8x60_PHY_REG2_PD_DRIVE_1 | 167 HDMI_8x60_PHY_REG2_PD_DESER); 168 udelay(10); 169 /* Disable PLL */ 170 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG3, 0); 171 /* Power down PHY, but keep RX-sense: */ 172 hdmi_write(hdmi, REG_HDMI_8x60_PHY_REG2, 173 HDMI_8x60_PHY_REG2_RCV_SENSE_EN | 174 HDMI_8x60_PHY_REG2_PD_PWRGEN | 175 HDMI_8x60_PHY_REG2_PD_PLL | 176 HDMI_8x60_PHY_REG2_PD_DRIVE_4 | 177 HDMI_8x60_PHY_REG2_PD_DRIVE_3 | 178 HDMI_8x60_PHY_REG2_PD_DRIVE_2 | 179 HDMI_8x60_PHY_REG2_PD_DRIVE_1 | 180 HDMI_8x60_PHY_REG2_PD_DESER); 181 } 182 183 static const struct hdmi_phy_funcs hdmi_phy_8x60_funcs = { 184 .destroy = hdmi_phy_8x60_destroy, 185 .reset = hdmi_phy_8x60_reset, 186 .powerup = hdmi_phy_8x60_powerup, 187 .powerdown = hdmi_phy_8x60_powerdown, 188 }; 189 190 struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi) 191 { 192 struct hdmi_phy_8x60 *phy_8x60; 193 struct hdmi_phy *phy = NULL; 194 int ret; 195 196 phy_8x60 = kzalloc(sizeof(*phy_8x60), GFP_KERNEL); 197 if (!phy_8x60) { 198 ret = -ENOMEM; 199 goto fail; 200 } 201 202 phy = &phy_8x60->base; 203 204 phy->funcs = &hdmi_phy_8x60_funcs; 205 206 phy_8x60->hdmi = hdmi; 207 208 return phy; 209 210 fail: 211 if (phy) 212 hdmi_phy_8x60_destroy(phy); 213 return ERR_PTR(ret); 214 } 215