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 #ifdef CONFIG_COMMON_CLK 19 #include <linux/clk.h> 20 #include <linux/clk-provider.h> 21 #endif 22 23 #include "hdmi.h" 24 25 struct hdmi_phy_8960 { 26 struct hdmi_phy base; 27 struct hdmi *hdmi; 28 #ifdef CONFIG_COMMON_CLK 29 struct clk_hw pll_hw; 30 struct clk *pll; 31 unsigned long pixclk; 32 #endif 33 }; 34 #define to_hdmi_phy_8960(x) container_of(x, struct hdmi_phy_8960, base) 35 36 #ifdef CONFIG_COMMON_CLK 37 #define clk_to_phy(x) container_of(x, struct hdmi_phy_8960, pll_hw) 38 39 /* 40 * HDMI PLL: 41 * 42 * To get the parent clock setup properly, we need to plug in hdmi pll 43 * configuration into common-clock-framework. 44 */ 45 46 struct pll_rate { 47 unsigned long rate; 48 struct { 49 uint32_t val; 50 uint32_t reg; 51 } conf[32]; 52 }; 53 54 /* NOTE: keep sorted highest freq to lowest: */ 55 static const struct pll_rate freqtbl[] = { 56 { 154000000, { 57 { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 58 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 59 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 60 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 61 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 62 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 63 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 64 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 65 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 66 { 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 67 { 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 68 { 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 69 { 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 70 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 71 { 0, 0 } } 72 }, 73 /* 1080p60/1080p50 case */ 74 { 148500000, { 75 { 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 76 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, 77 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 78 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 79 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, 80 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, 81 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, 82 { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 83 { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 84 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 85 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 86 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 87 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, 88 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, 89 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, 90 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, 91 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, 92 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, 93 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, 94 { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 95 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 96 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 97 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 98 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 99 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 100 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, 101 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, 102 { 0, 0 } } 103 }, 104 { 108000000, { 105 { 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 106 { 0x21, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 107 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 108 { 0x1c, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 109 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 110 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 111 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 112 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 113 { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 114 { 0x49, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 115 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 116 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 117 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 118 { 0, 0 } } 119 }, 120 /* 720p60/720p50/1080i60/1080i50/1080p24/1080p30/1080p25 */ 121 { 74250000, { 122 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, 123 { 0x12, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 124 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 125 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 126 { 0x76, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 127 { 0xe6, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 128 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 129 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 130 { 0, 0 } } 131 }, 132 { 74176000, { 133 { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 134 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 135 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 136 { 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 137 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 138 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 139 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 140 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 141 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 142 { 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 143 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 144 { 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 145 { 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 146 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 147 { 0, 0 } } 148 }, 149 { 65000000, { 150 { 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 151 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 152 { 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 153 { 0x8a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 154 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 155 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 156 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 157 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 158 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 159 { 0x0b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 160 { 0x4b, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 161 { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 162 { 0x09, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 163 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 164 { 0, 0 } } 165 }, 166 /* 480p60/480i60 */ 167 { 27030000, { 168 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, 169 { 0x38, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 170 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, 171 { 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 172 { 0xff, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 173 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 174 { 0x4e, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 175 { 0xd7, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 176 { 0x03, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 177 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 178 { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 179 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 180 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 181 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 182 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 183 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 184 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, 185 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, 186 { 0, 0 } } 187 }, 188 /* 576p50/576i50 */ 189 { 27000000, { 190 { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 191 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, 192 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 193 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 194 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, 195 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, 196 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, 197 { 0x7b, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 198 { 0x01, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 199 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 200 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 201 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 202 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, 203 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, 204 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, 205 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, 206 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, 207 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, 208 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, 209 { 0x2a, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 210 { 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 211 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 212 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 213 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 214 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 215 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, 216 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, 217 { 0, 0 } } 218 }, 219 /* 640x480p60 */ 220 { 25200000, { 221 { 0x32, REG_HDMI_8960_PHY_PLL_REFCLK_CFG }, 222 { 0x02, REG_HDMI_8960_PHY_PLL_CHRG_PUMP_CFG }, 223 { 0x01, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 }, 224 { 0x33, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 }, 225 { 0x2c, REG_HDMI_8960_PHY_PLL_IDAC_ADJ_CFG }, 226 { 0x06, REG_HDMI_8960_PHY_PLL_I_VI_KVCO_CFG }, 227 { 0x0a, REG_HDMI_8960_PHY_PLL_PWRDN_B }, 228 { 0x77, REG_HDMI_8960_PHY_PLL_SDM_CFG0 }, 229 { 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 }, 230 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG2 }, 231 { 0xc0, REG_HDMI_8960_PHY_PLL_SDM_CFG3 }, 232 { 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 }, 233 { 0x9a, REG_HDMI_8960_PHY_PLL_SSC_CFG0 }, 234 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG1 }, 235 { 0x00, REG_HDMI_8960_PHY_PLL_SSC_CFG2 }, 236 { 0x20, REG_HDMI_8960_PHY_PLL_SSC_CFG3 }, 237 { 0x10, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0 }, 238 { 0x1a, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1 }, 239 { 0x0d, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2 }, 240 { 0xf4, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 }, 241 { 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 }, 242 { 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 }, 243 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 }, 244 { 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 }, 245 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 }, 246 { 0x33, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG6 }, 247 { 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG7 }, 248 { 0, 0 } } 249 }, 250 }; 251 252 static int hdmi_pll_enable(struct clk_hw *hw) 253 { 254 struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw); 255 struct hdmi *hdmi = phy_8960->hdmi; 256 int timeout_count, pll_lock_retry = 10; 257 unsigned int val; 258 259 DBG(""); 260 261 /* Assert PLL S/W reset */ 262 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); 263 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG0, 0x10); 264 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG1, 0x1a); 265 266 /* Wait for a short time before de-asserting 267 * to allow the hardware to complete its job. 268 * This much of delay should be fine for hardware 269 * to assert and de-assert. 270 */ 271 udelay(10); 272 273 /* De-assert PLL S/W reset */ 274 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); 275 276 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12); 277 val |= HDMI_8960_PHY_REG12_SW_RESET; 278 /* Assert PHY S/W reset */ 279 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val); 280 val &= ~HDMI_8960_PHY_REG12_SW_RESET; 281 /* Wait for a short time before de-asserting 282 to allow the hardware to complete its job. 283 This much of delay should be fine for hardware 284 to assert and de-assert. */ 285 udelay(10); 286 /* De-assert PHY S/W reset */ 287 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val); 288 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x3f); 289 290 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12); 291 val |= HDMI_8960_PHY_REG12_PWRDN_B; 292 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val); 293 /* Wait 10 us for enabling global power for PHY */ 294 mb(); 295 udelay(10); 296 297 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B); 298 val |= HDMI_8960_PHY_PLL_PWRDN_B_PLL_PWRDN_B; 299 val &= ~HDMI_8960_PHY_PLL_PWRDN_B_PD_PLL; 300 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); 301 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x80); 302 303 timeout_count = 1000; 304 while (--pll_lock_retry > 0) { 305 306 /* are we there yet? */ 307 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_STATUS0); 308 if (val & HDMI_8960_PHY_PLL_STATUS0_PLL_LOCK) 309 break; 310 311 udelay(1); 312 313 if (--timeout_count > 0) 314 continue; 315 316 /* 317 * PLL has still not locked. 318 * Do a software reset and try again 319 * Assert PLL S/W reset first 320 */ 321 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x8d); 322 udelay(10); 323 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_LOCKDET_CFG2, 0x0d); 324 325 /* 326 * Wait for a short duration for the PLL calibration 327 * before checking if the PLL gets locked 328 */ 329 udelay(350); 330 331 timeout_count = 1000; 332 } 333 334 return 0; 335 } 336 337 static void hdmi_pll_disable(struct clk_hw *hw) 338 { 339 struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw); 340 struct hdmi *hdmi = phy_8960->hdmi; 341 unsigned int val; 342 343 DBG(""); 344 345 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_REG12); 346 val &= ~HDMI_8960_PHY_REG12_PWRDN_B; 347 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG12, val); 348 349 val = hdmi_read(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B); 350 val |= HDMI_8960_PHY_REG12_SW_RESET; 351 val &= ~HDMI_8960_PHY_REG12_PWRDN_B; 352 hdmi_write(hdmi, REG_HDMI_8960_PHY_PLL_PWRDN_B, val); 353 /* Make sure HDMI PHY/PLL are powered down */ 354 mb(); 355 } 356 357 static const struct pll_rate *find_rate(unsigned long rate) 358 { 359 int i; 360 for (i = 1; i < ARRAY_SIZE(freqtbl); i++) 361 if (rate > freqtbl[i].rate) 362 return &freqtbl[i-1]; 363 return &freqtbl[i-1]; 364 } 365 366 static unsigned long hdmi_pll_recalc_rate(struct clk_hw *hw, 367 unsigned long parent_rate) 368 { 369 struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw); 370 return phy_8960->pixclk; 371 } 372 373 static long hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, 374 unsigned long *parent_rate) 375 { 376 const struct pll_rate *pll_rate = find_rate(rate); 377 return pll_rate->rate; 378 } 379 380 static int hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, 381 unsigned long parent_rate) 382 { 383 struct hdmi_phy_8960 *phy_8960 = clk_to_phy(hw); 384 struct hdmi *hdmi = phy_8960->hdmi; 385 const struct pll_rate *pll_rate = find_rate(rate); 386 int i; 387 388 DBG("rate=%lu", rate); 389 390 for (i = 0; pll_rate->conf[i].reg; i++) 391 hdmi_write(hdmi, pll_rate->conf[i].reg, pll_rate->conf[i].val); 392 393 phy_8960->pixclk = rate; 394 395 return 0; 396 } 397 398 399 static const struct clk_ops hdmi_pll_ops = { 400 .enable = hdmi_pll_enable, 401 .disable = hdmi_pll_disable, 402 .recalc_rate = hdmi_pll_recalc_rate, 403 .round_rate = hdmi_pll_round_rate, 404 .set_rate = hdmi_pll_set_rate, 405 }; 406 407 static const char *hdmi_pll_parents[] = { 408 "pxo", 409 }; 410 411 static struct clk_init_data pll_init = { 412 .name = "hdmi_pll", 413 .ops = &hdmi_pll_ops, 414 .parent_names = hdmi_pll_parents, 415 .num_parents = ARRAY_SIZE(hdmi_pll_parents), 416 }; 417 #endif 418 419 /* 420 * HDMI Phy: 421 */ 422 423 static void hdmi_phy_8960_destroy(struct hdmi_phy *phy) 424 { 425 struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); 426 kfree(phy_8960); 427 } 428 429 static void hdmi_phy_8960_reset(struct hdmi_phy *phy) 430 { 431 struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); 432 struct hdmi *hdmi = phy_8960->hdmi; 433 unsigned int val; 434 435 val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); 436 437 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 438 /* pull low */ 439 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 440 val & ~HDMI_PHY_CTRL_SW_RESET); 441 } else { 442 /* pull high */ 443 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 444 val | HDMI_PHY_CTRL_SW_RESET); 445 } 446 447 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { 448 /* pull low */ 449 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 450 val & ~HDMI_PHY_CTRL_SW_RESET_PLL); 451 } else { 452 /* pull high */ 453 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 454 val | HDMI_PHY_CTRL_SW_RESET_PLL); 455 } 456 457 msleep(100); 458 459 if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { 460 /* pull high */ 461 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 462 val | HDMI_PHY_CTRL_SW_RESET); 463 } else { 464 /* pull low */ 465 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 466 val & ~HDMI_PHY_CTRL_SW_RESET); 467 } 468 469 if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { 470 /* pull high */ 471 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 472 val | HDMI_PHY_CTRL_SW_RESET_PLL); 473 } else { 474 /* pull low */ 475 hdmi_write(hdmi, REG_HDMI_PHY_CTRL, 476 val & ~HDMI_PHY_CTRL_SW_RESET_PLL); 477 } 478 } 479 480 static void hdmi_phy_8960_powerup(struct hdmi_phy *phy, 481 unsigned long int pixclock) 482 { 483 struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); 484 struct hdmi *hdmi = phy_8960->hdmi; 485 486 DBG("pixclock: %lu", pixclock); 487 488 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x00); 489 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG0, 0x1b); 490 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG1, 0xf2); 491 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG4, 0x00); 492 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG5, 0x00); 493 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG6, 0x00); 494 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG7, 0x00); 495 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG8, 0x00); 496 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG9, 0x00); 497 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG10, 0x00); 498 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG11, 0x00); 499 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG3, 0x20); 500 } 501 502 static void hdmi_phy_8960_powerdown(struct hdmi_phy *phy) 503 { 504 struct hdmi_phy_8960 *phy_8960 = to_hdmi_phy_8960(phy); 505 struct hdmi *hdmi = phy_8960->hdmi; 506 507 DBG(""); 508 509 hdmi_write(hdmi, REG_HDMI_8960_PHY_REG2, 0x7f); 510 } 511 512 static const struct hdmi_phy_funcs hdmi_phy_8960_funcs = { 513 .destroy = hdmi_phy_8960_destroy, 514 .reset = hdmi_phy_8960_reset, 515 .powerup = hdmi_phy_8960_powerup, 516 .powerdown = hdmi_phy_8960_powerdown, 517 }; 518 519 struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi) 520 { 521 struct hdmi_phy_8960 *phy_8960; 522 struct hdmi_phy *phy = NULL; 523 int ret; 524 #ifdef CONFIG_COMMON_CLK 525 int i; 526 527 /* sanity check: */ 528 for (i = 0; i < (ARRAY_SIZE(freqtbl) - 1); i++) 529 if (WARN_ON(freqtbl[i].rate < freqtbl[i+1].rate)) 530 return ERR_PTR(-EINVAL); 531 #endif 532 533 phy_8960 = kzalloc(sizeof(*phy_8960), GFP_KERNEL); 534 if (!phy_8960) { 535 ret = -ENOMEM; 536 goto fail; 537 } 538 539 phy = &phy_8960->base; 540 541 phy->funcs = &hdmi_phy_8960_funcs; 542 543 phy_8960->hdmi = hdmi; 544 545 #ifdef CONFIG_COMMON_CLK 546 phy_8960->pll_hw.init = &pll_init; 547 phy_8960->pll = devm_clk_register(&hdmi->pdev->dev, &phy_8960->pll_hw); 548 if (IS_ERR(phy_8960->pll)) { 549 ret = PTR_ERR(phy_8960->pll); 550 phy_8960->pll = NULL; 551 goto fail; 552 } 553 #endif 554 555 return phy; 556 557 fail: 558 if (phy) 559 hdmi_phy_8960_destroy(phy); 560 return ERR_PTR(ret); 561 } 562