18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2017 Rockchip Electronics Co. Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Zheng Yang <zhengyang@rock-chips.com> 68c2ecf20Sopenharmony_ci * Heiko Stuebner <heiko@sntech.de> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/nvmem-consumer.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/regmap.h> 218c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* REG: 0x00 */ 278c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_REFCLK_SEL_PCLK BIT(0) 288c2ecf20Sopenharmony_ci/* REG: 0x01 */ 298c2ecf20Sopenharmony_ci#define RK3228_BYPASS_RXSENSE_EN BIT(2) 308c2ecf20Sopenharmony_ci#define RK3228_BYPASS_PWRON_EN BIT(1) 318c2ecf20Sopenharmony_ci#define RK3228_BYPASS_PLLPD_EN BIT(0) 328c2ecf20Sopenharmony_ci/* REG: 0x02 */ 338c2ecf20Sopenharmony_ci#define RK3228_BYPASS_PDATA_EN BIT(4) 348c2ecf20Sopenharmony_ci#define RK3228_PDATAEN_DISABLE BIT(0) 358c2ecf20Sopenharmony_ci/* REG: 0x03 */ 368c2ecf20Sopenharmony_ci#define RK3228_BYPASS_AUTO_TERM_RES_CAL BIT(7) 378c2ecf20Sopenharmony_ci#define RK3228_AUTO_TERM_RES_CAL_SPEED_14_8(x) UPDATE(x, 6, 0) 388c2ecf20Sopenharmony_ci/* REG: 0x04 */ 398c2ecf20Sopenharmony_ci#define RK3228_AUTO_TERM_RES_CAL_SPEED_7_0(x) UPDATE(x, 7, 0) 408c2ecf20Sopenharmony_ci/* REG: 0xaa */ 418c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_CTRL_MANUAL BIT(0) 428c2ecf20Sopenharmony_ci/* REG: 0xe0 */ 438c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_POWER_DOWN BIT(5) 448c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_POWER_DOWN BIT(4) 458c2ecf20Sopenharmony_ci#define RK3228_RXSENSE_CLK_CH_ENABLE BIT(3) 468c2ecf20Sopenharmony_ci#define RK3228_RXSENSE_DATA_CH2_ENABLE BIT(2) 478c2ecf20Sopenharmony_ci#define RK3228_RXSENSE_DATA_CH1_ENABLE BIT(1) 488c2ecf20Sopenharmony_ci#define RK3228_RXSENSE_DATA_CH0_ENABLE BIT(0) 498c2ecf20Sopenharmony_ci/* REG: 0xe1 */ 508c2ecf20Sopenharmony_ci#define RK3228_BANDGAP_ENABLE BIT(4) 518c2ecf20Sopenharmony_ci#define RK3228_TMDS_DRIVER_ENABLE GENMASK(3, 0) 528c2ecf20Sopenharmony_ci/* REG: 0xe2 */ 538c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_FB_DIV_8_MASK BIT(7) 548c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) 558c2ecf20Sopenharmony_ci#define RK3228_PCLK_VCO_DIV_5_MASK BIT(5) 568c2ecf20Sopenharmony_ci#define RK3228_PCLK_VCO_DIV_5(x) UPDATE(x, 5, 5) 578c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PRE_DIV_MASK GENMASK(4, 0) 588c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PRE_DIV(x) UPDATE(x, 4, 0) 598c2ecf20Sopenharmony_ci/* REG: 0xe3 */ 608c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) 618c2ecf20Sopenharmony_ci/* REG: 0xe4 */ 628c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) 638c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_B_SHIFT 5 648c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) 658c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) 668c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) 678c2ecf20Sopenharmony_ci/* REG: 0xe5 */ 688c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) 698c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) 708c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) 718c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) 728c2ecf20Sopenharmony_ci/* REG: 0xe6 */ 738c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(5, 4) 748c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 5, 4) 758c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(3, 2) 768c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 3, 2) 778c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(1, 0) 788c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 1, 0) 798c2ecf20Sopenharmony_ci/* REG: 0xe8 */ 808c2ecf20Sopenharmony_ci#define RK3228_PRE_PLL_LOCK_STATUS BIT(0) 818c2ecf20Sopenharmony_ci/* REG: 0xe9 */ 828c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_POST_DIV_ENABLE UPDATE(3, 7, 6) 838c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_PRE_DIV_MASK GENMASK(4, 0) 848c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) 858c2ecf20Sopenharmony_ci/* REG: 0xea */ 868c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) 878c2ecf20Sopenharmony_ci/* REG: 0xeb */ 888c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_FB_DIV_8_MASK BIT(7) 898c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) 908c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_POST_DIV_MASK GENMASK(5, 4) 918c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_POST_DIV(x) UPDATE(x, 5, 4) 928c2ecf20Sopenharmony_ci#define RK3228_POST_PLL_LOCK_STATUS BIT(0) 938c2ecf20Sopenharmony_ci/* REG: 0xee */ 948c2ecf20Sopenharmony_ci#define RK3228_TMDS_CH_TA_ENABLE GENMASK(7, 4) 958c2ecf20Sopenharmony_ci/* REG: 0xef */ 968c2ecf20Sopenharmony_ci#define RK3228_TMDS_CLK_CH_TA(x) UPDATE(x, 7, 6) 978c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH2_TA(x) UPDATE(x, 5, 4) 988c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH1_TA(x) UPDATE(x, 3, 2) 998c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH0_TA(x) UPDATE(x, 1, 0) 1008c2ecf20Sopenharmony_ci/* REG: 0xf0 */ 1018c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS_MASK GENMASK(5, 4) 1028c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH2_PRE_EMPHASIS(x) UPDATE(x, 5, 4) 1038c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS_MASK GENMASK(3, 2) 1048c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH1_PRE_EMPHASIS(x) UPDATE(x, 3, 2) 1058c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS_MASK GENMASK(1, 0) 1068c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH0_PRE_EMPHASIS(x) UPDATE(x, 1, 0) 1078c2ecf20Sopenharmony_ci/* REG: 0xf1 */ 1088c2ecf20Sopenharmony_ci#define RK3228_TMDS_CLK_CH_OUTPUT_SWING(x) UPDATE(x, 7, 4) 1098c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH2_OUTPUT_SWING(x) UPDATE(x, 3, 0) 1108c2ecf20Sopenharmony_ci/* REG: 0xf2 */ 1118c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH1_OUTPUT_SWING(x) UPDATE(x, 7, 4) 1128c2ecf20Sopenharmony_ci#define RK3228_TMDS_DATA_CH0_OUTPUT_SWING(x) UPDATE(x, 3, 0) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* REG: 0x01 */ 1158c2ecf20Sopenharmony_ci#define RK3328_BYPASS_RXSENSE_EN BIT(2) 1168c2ecf20Sopenharmony_ci#define RK3328_BYPASS_POWERON_EN BIT(1) 1178c2ecf20Sopenharmony_ci#define RK3328_BYPASS_PLLPD_EN BIT(0) 1188c2ecf20Sopenharmony_ci/* REG: 0x02 */ 1198c2ecf20Sopenharmony_ci#define RK3328_INT_POL_HIGH BIT(7) 1208c2ecf20Sopenharmony_ci#define RK3328_BYPASS_PDATA_EN BIT(4) 1218c2ecf20Sopenharmony_ci#define RK3328_PDATA_EN BIT(0) 1228c2ecf20Sopenharmony_ci/* REG:0x05 */ 1238c2ecf20Sopenharmony_ci#define RK3328_INT_TMDS_CLK(x) UPDATE(x, 7, 4) 1248c2ecf20Sopenharmony_ci#define RK3328_INT_TMDS_D2(x) UPDATE(x, 3, 0) 1258c2ecf20Sopenharmony_ci/* REG:0x07 */ 1268c2ecf20Sopenharmony_ci#define RK3328_INT_TMDS_D1(x) UPDATE(x, 7, 4) 1278c2ecf20Sopenharmony_ci#define RK3328_INT_TMDS_D0(x) UPDATE(x, 3, 0) 1288c2ecf20Sopenharmony_ci/* for all RK3328_INT_TMDS_*, ESD_DET as defined in 0xc8-0xcb */ 1298c2ecf20Sopenharmony_ci#define RK3328_INT_AGND_LOW_PULSE_LOCKED BIT(3) 1308c2ecf20Sopenharmony_ci#define RK3328_INT_RXSENSE_LOW_PULSE_LOCKED BIT(2) 1318c2ecf20Sopenharmony_ci#define RK3328_INT_VSS_AGND_ESD_DET BIT(1) 1328c2ecf20Sopenharmony_ci#define RK3328_INT_AGND_VSS_ESD_DET BIT(0) 1338c2ecf20Sopenharmony_ci/* REG: 0xa0 */ 1348c2ecf20Sopenharmony_ci#define RK3328_PCLK_VCO_DIV_5_MASK BIT(1) 1358c2ecf20Sopenharmony_ci#define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) 1368c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_POWER_DOWN BIT(0) 1378c2ecf20Sopenharmony_ci/* REG: 0xa1 */ 1388c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) 1398c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) 1408c2ecf20Sopenharmony_ci/* REG: 0xa2 */ 1418c2ecf20Sopenharmony_ci/* unset means center spread */ 1428c2ecf20Sopenharmony_ci#define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7) 1438c2ecf20Sopenharmony_ci#define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) 1448c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) 1458c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) 1468c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) 1478c2ecf20Sopenharmony_ci/* REG: 0xa3 */ 1488c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) 1498c2ecf20Sopenharmony_ci/* REG: 0xa4*/ 1508c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) 1518c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) 1528c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) 1538c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) 1548c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) 1558c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) 1568c2ecf20Sopenharmony_ci/* REG: 0xa5 */ 1578c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5 1588c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) 1598c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) 1608c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) 1618c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) 1628c2ecf20Sopenharmony_ci/* REG: 0xa6 */ 1638c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5 1648c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) 1658c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) 1668c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) 1678c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) 1688c2ecf20Sopenharmony_ci/* REG: 0xa9 */ 1698c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_LOCK_STATUS BIT(0) 1708c2ecf20Sopenharmony_ci/* REG: 0xaa */ 1718c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) 1728c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1) 1738c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POWER_DOWN BIT(0) 1748c2ecf20Sopenharmony_ci/* REG:0xab */ 1758c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) 1768c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) 1778c2ecf20Sopenharmony_ci/* REG: 0xac */ 1788c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) 1798c2ecf20Sopenharmony_ci/* REG: 0xad */ 1808c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POST_DIV_MASK GENMASK(1, 0) 1818c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POST_DIV_2 0x0 1828c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POST_DIV_4 0x1 1838c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_POST_DIV_8 0x3 1848c2ecf20Sopenharmony_ci/* REG: 0xaf */ 1858c2ecf20Sopenharmony_ci#define RK3328_POST_PLL_LOCK_STATUS BIT(0) 1868c2ecf20Sopenharmony_ci/* REG: 0xb0 */ 1878c2ecf20Sopenharmony_ci#define RK3328_BANDGAP_ENABLE BIT(2) 1888c2ecf20Sopenharmony_ci/* REG: 0xb2 */ 1898c2ecf20Sopenharmony_ci#define RK3328_TMDS_CLK_DRIVER_EN BIT(3) 1908c2ecf20Sopenharmony_ci#define RK3328_TMDS_D2_DRIVER_EN BIT(2) 1918c2ecf20Sopenharmony_ci#define RK3328_TMDS_D1_DRIVER_EN BIT(1) 1928c2ecf20Sopenharmony_ci#define RK3328_TMDS_D0_DRIVER_EN BIT(0) 1938c2ecf20Sopenharmony_ci#define RK3328_TMDS_DRIVER_ENABLE (RK3328_TMDS_CLK_DRIVER_EN | \ 1948c2ecf20Sopenharmony_ci RK3328_TMDS_D2_DRIVER_EN | \ 1958c2ecf20Sopenharmony_ci RK3328_TMDS_D1_DRIVER_EN | \ 1968c2ecf20Sopenharmony_ci RK3328_TMDS_D0_DRIVER_EN) 1978c2ecf20Sopenharmony_ci/* REG:0xc5 */ 1988c2ecf20Sopenharmony_ci#define RK3328_BYPASS_TERM_RESISTOR_CALIB BIT(7) 1998c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(x) UPDATE((x) >> 8, 6, 0) 2008c2ecf20Sopenharmony_ci/* REG:0xc6 */ 2018c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(x) UPDATE(x, 7, 0) 2028c2ecf20Sopenharmony_ci/* REG:0xc7 */ 2038c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_50 UPDATE(0, 2, 1) 2048c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_62_5 UPDATE(1, 2, 1) 2058c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_75 UPDATE(2, 2, 1) 2068c2ecf20Sopenharmony_ci#define RK3328_TERM_RESISTOR_100 UPDATE(3, 2, 1) 2078c2ecf20Sopenharmony_ci/* REG 0xc8 - 0xcb */ 2088c2ecf20Sopenharmony_ci#define RK3328_ESD_DETECT_MASK GENMASK(7, 6) 2098c2ecf20Sopenharmony_ci#define RK3328_ESD_DETECT_340MV (0x0 << 6) 2108c2ecf20Sopenharmony_ci#define RK3328_ESD_DETECT_280MV (0x1 << 6) 2118c2ecf20Sopenharmony_ci#define RK3328_ESD_DETECT_260MV (0x2 << 6) 2128c2ecf20Sopenharmony_ci#define RK3328_ESD_DETECT_240MV (0x3 << 6) 2138c2ecf20Sopenharmony_ci/* resistors can be used in parallel */ 2148c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_MASK GENMASK(5, 0) 2158c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_75 BIT(5) 2168c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_150 BIT(4) 2178c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_300 BIT(3) 2188c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_600 BIT(2) 2198c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_1000 BIT(1) 2208c2ecf20Sopenharmony_ci#define RK3328_TMDS_TERM_RESIST_2000 BIT(0) 2218c2ecf20Sopenharmony_ci/* REG: 0xd1 */ 2228c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) 2238c2ecf20Sopenharmony_ci/* REG: 0xd2 */ 2248c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) 2258c2ecf20Sopenharmony_ci/* REG: 0xd3 */ 2268c2ecf20Sopenharmony_ci#define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistruct inno_hdmi_phy_drv_data; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistruct inno_hdmi_phy { 2318c2ecf20Sopenharmony_ci struct device *dev; 2328c2ecf20Sopenharmony_ci struct regmap *regmap; 2338c2ecf20Sopenharmony_ci int irq; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci struct phy *phy; 2368c2ecf20Sopenharmony_ci struct clk *sysclk; 2378c2ecf20Sopenharmony_ci struct clk *refoclk; 2388c2ecf20Sopenharmony_ci struct clk *refpclk; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* platform data */ 2418c2ecf20Sopenharmony_ci const struct inno_hdmi_phy_drv_data *plat_data; 2428c2ecf20Sopenharmony_ci int chip_version; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* clk provider */ 2458c2ecf20Sopenharmony_ci struct clk_hw hw; 2468c2ecf20Sopenharmony_ci struct clk *phyclk; 2478c2ecf20Sopenharmony_ci unsigned long pixclock; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistruct pre_pll_config { 2518c2ecf20Sopenharmony_ci unsigned long pixclock; 2528c2ecf20Sopenharmony_ci unsigned long tmdsclock; 2538c2ecf20Sopenharmony_ci u8 prediv; 2548c2ecf20Sopenharmony_ci u16 fbdiv; 2558c2ecf20Sopenharmony_ci u8 tmds_div_a; 2568c2ecf20Sopenharmony_ci u8 tmds_div_b; 2578c2ecf20Sopenharmony_ci u8 tmds_div_c; 2588c2ecf20Sopenharmony_ci u8 pclk_div_a; 2598c2ecf20Sopenharmony_ci u8 pclk_div_b; 2608c2ecf20Sopenharmony_ci u8 pclk_div_c; 2618c2ecf20Sopenharmony_ci u8 pclk_div_d; 2628c2ecf20Sopenharmony_ci u8 vco_div_5_en; 2638c2ecf20Sopenharmony_ci u32 fracdiv; 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistruct post_pll_config { 2678c2ecf20Sopenharmony_ci unsigned long tmdsclock; 2688c2ecf20Sopenharmony_ci u8 prediv; 2698c2ecf20Sopenharmony_ci u16 fbdiv; 2708c2ecf20Sopenharmony_ci u8 postdiv; 2718c2ecf20Sopenharmony_ci u8 version; 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistruct phy_config { 2758c2ecf20Sopenharmony_ci unsigned long tmdsclock; 2768c2ecf20Sopenharmony_ci u8 regs[14]; 2778c2ecf20Sopenharmony_ci}; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistruct inno_hdmi_phy_ops { 2808c2ecf20Sopenharmony_ci int (*init)(struct inno_hdmi_phy *inno); 2818c2ecf20Sopenharmony_ci int (*power_on)(struct inno_hdmi_phy *inno, 2828c2ecf20Sopenharmony_ci const struct post_pll_config *cfg, 2838c2ecf20Sopenharmony_ci const struct phy_config *phy_cfg); 2848c2ecf20Sopenharmony_ci void (*power_off)(struct inno_hdmi_phy *inno); 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistruct inno_hdmi_phy_drv_data { 2888c2ecf20Sopenharmony_ci const struct inno_hdmi_phy_ops *ops; 2898c2ecf20Sopenharmony_ci const struct clk_ops *clk_ops; 2908c2ecf20Sopenharmony_ci const struct phy_config *phy_cfg_table; 2918c2ecf20Sopenharmony_ci}; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic const struct pre_pll_config pre_pll_cfg_table[] = { 2948c2ecf20Sopenharmony_ci { 27000000, 27000000, 1, 90, 3, 2, 2, 10, 3, 3, 4, 0, 0}, 2958c2ecf20Sopenharmony_ci { 27000000, 33750000, 1, 90, 1, 3, 3, 10, 3, 3, 4, 0, 0}, 2968c2ecf20Sopenharmony_ci { 40000000, 40000000, 1, 80, 2, 2, 2, 12, 2, 2, 2, 0, 0}, 2978c2ecf20Sopenharmony_ci { 59341000, 59341000, 1, 98, 3, 1, 2, 1, 3, 3, 4, 0, 0xE6AE6B}, 2988c2ecf20Sopenharmony_ci { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0}, 2998c2ecf20Sopenharmony_ci { 59341000, 74176250, 1, 98, 0, 3, 3, 1, 3, 3, 4, 0, 0xE6AE6B}, 3008c2ecf20Sopenharmony_ci { 59400000, 74250000, 1, 99, 1, 2, 2, 1, 3, 3, 4, 0, 0}, 3018c2ecf20Sopenharmony_ci { 74176000, 74176000, 1, 98, 1, 2, 2, 1, 2, 3, 4, 0, 0xE6AE6B}, 3028c2ecf20Sopenharmony_ci { 74250000, 74250000, 1, 99, 1, 2, 2, 1, 2, 3, 4, 0, 0}, 3038c2ecf20Sopenharmony_ci { 74176000, 92720000, 4, 494, 1, 2, 2, 1, 3, 3, 4, 0, 0x816817}, 3048c2ecf20Sopenharmony_ci { 74250000, 92812500, 4, 495, 1, 2, 2, 1, 3, 3, 4, 0, 0}, 3058c2ecf20Sopenharmony_ci {148352000, 148352000, 1, 98, 1, 1, 1, 1, 2, 2, 2, 0, 0xE6AE6B}, 3068c2ecf20Sopenharmony_ci {148500000, 148500000, 1, 99, 1, 1, 1, 1, 2, 2, 2, 0, 0}, 3078c2ecf20Sopenharmony_ci {148352000, 185440000, 4, 494, 0, 2, 2, 1, 3, 2, 2, 0, 0x816817}, 3088c2ecf20Sopenharmony_ci {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0}, 3098c2ecf20Sopenharmony_ci {296703000, 296703000, 1, 98, 0, 1, 1, 1, 0, 2, 2, 0, 0xE6AE6B}, 3108c2ecf20Sopenharmony_ci {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0}, 3118c2ecf20Sopenharmony_ci {296703000, 370878750, 4, 494, 1, 2, 0, 1, 3, 1, 1, 0, 0x816817}, 3128c2ecf20Sopenharmony_ci {297000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 0, 0}, 3138c2ecf20Sopenharmony_ci {593407000, 296703500, 1, 98, 0, 1, 1, 1, 0, 2, 1, 0, 0xE6AE6B}, 3148c2ecf20Sopenharmony_ci {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 1, 0, 0}, 3158c2ecf20Sopenharmony_ci {593407000, 370879375, 4, 494, 1, 2, 0, 1, 3, 1, 1, 1, 0x816817}, 3168c2ecf20Sopenharmony_ci {594000000, 371250000, 4, 495, 1, 2, 0, 1, 3, 1, 1, 1, 0}, 3178c2ecf20Sopenharmony_ci {593407000, 593407000, 1, 98, 0, 2, 0, 1, 0, 1, 1, 0, 0xE6AE6B}, 3188c2ecf20Sopenharmony_ci {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0}, 3198c2ecf20Sopenharmony_ci { /* sentinel */ } 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic const struct post_pll_config post_pll_cfg_table[] = { 3238c2ecf20Sopenharmony_ci {33750000, 1, 40, 8, 1}, 3248c2ecf20Sopenharmony_ci {33750000, 1, 80, 8, 2}, 3258c2ecf20Sopenharmony_ci {74250000, 1, 40, 8, 1}, 3268c2ecf20Sopenharmony_ci {74250000, 18, 80, 8, 2}, 3278c2ecf20Sopenharmony_ci {148500000, 2, 40, 4, 3}, 3288c2ecf20Sopenharmony_ci {297000000, 4, 40, 2, 3}, 3298c2ecf20Sopenharmony_ci {594000000, 8, 40, 1, 3}, 3308c2ecf20Sopenharmony_ci { /* sentinel */ } 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* phy tuning values for an undocumented set of registers */ 3348c2ecf20Sopenharmony_cistatic const struct phy_config rk3228_phy_cfg[] = { 3358c2ecf20Sopenharmony_ci { 165000000, { 3368c2ecf20Sopenharmony_ci 0xaa, 0x00, 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 3378c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 3388c2ecf20Sopenharmony_ci }, 3398c2ecf20Sopenharmony_ci }, { 3408c2ecf20Sopenharmony_ci 340000000, { 3418c2ecf20Sopenharmony_ci 0xaa, 0x15, 0x6a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 3428c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 3438c2ecf20Sopenharmony_ci }, 3448c2ecf20Sopenharmony_ci }, { 3458c2ecf20Sopenharmony_ci 594000000, { 3468c2ecf20Sopenharmony_ci 0xaa, 0x15, 0x7a, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 3478c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci }, { /* sentinel */ }, 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* phy tuning values for an undocumented set of registers */ 3538c2ecf20Sopenharmony_cistatic const struct phy_config rk3328_phy_cfg[] = { 3548c2ecf20Sopenharmony_ci { 165000000, { 3558c2ecf20Sopenharmony_ci 0x07, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x08, 0x08, 3568c2ecf20Sopenharmony_ci 0x00, 0xac, 0xcc, 0xcc, 0xcc, 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci }, { 3598c2ecf20Sopenharmony_ci 340000000, { 3608c2ecf20Sopenharmony_ci 0x0b, 0x0d, 0x0d, 0x0d, 0x07, 0x15, 0x08, 0x08, 0x08, 3618c2ecf20Sopenharmony_ci 0x3f, 0xac, 0xcc, 0xcd, 0xdd, 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci }, { 3648c2ecf20Sopenharmony_ci 594000000, { 3658c2ecf20Sopenharmony_ci 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08, 3668c2ecf20Sopenharmony_ci 0x00, 0xac, 0xcc, 0xcc, 0xcc, 3678c2ecf20Sopenharmony_ci }, 3688c2ecf20Sopenharmony_ci }, { /* sentinel */ }, 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic inline struct inno_hdmi_phy *to_inno_hdmi_phy(struct clk_hw *hw) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci return container_of(hw, struct inno_hdmi_phy, hw); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* 3778c2ecf20Sopenharmony_ci * The register description of the IP block does not use any distinct names 3788c2ecf20Sopenharmony_ci * but instead the databook simply numbers the registers in one-increments. 3798c2ecf20Sopenharmony_ci * As the registers are obviously 32bit sized, the inno_* functions 3808c2ecf20Sopenharmony_ci * translate the databook register names to the actual registers addresses. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistatic inline void inno_write(struct inno_hdmi_phy *inno, u32 reg, u8 val) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci regmap_write(inno->regmap, reg * 4, val); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic inline u8 inno_read(struct inno_hdmi_phy *inno, u32 reg) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci u32 val; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci regmap_read(inno->regmap, reg * 4, &val); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return val; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic inline void inno_update_bits(struct inno_hdmi_phy *inno, u8 reg, 3978c2ecf20Sopenharmony_ci u8 mask, u8 val) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci regmap_update_bits(inno->regmap, reg * 4, mask, val); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#define inno_poll(inno, reg, val, cond, sleep_us, timeout_us) \ 4038c2ecf20Sopenharmony_ci regmap_read_poll_timeout((inno)->regmap, (reg) * 4, val, cond, \ 4048c2ecf20Sopenharmony_ci sleep_us, timeout_us) 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic unsigned long inno_hdmi_phy_get_tmdsclk(struct inno_hdmi_phy *inno, 4078c2ecf20Sopenharmony_ci unsigned long rate) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci int bus_width = phy_get_bus_width(inno->phy); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci switch (bus_width) { 4128c2ecf20Sopenharmony_ci case 4: 4138c2ecf20Sopenharmony_ci case 5: 4148c2ecf20Sopenharmony_ci case 6: 4158c2ecf20Sopenharmony_ci case 10: 4168c2ecf20Sopenharmony_ci case 12: 4178c2ecf20Sopenharmony_ci case 16: 4188c2ecf20Sopenharmony_ci return (u64)rate * bus_width / 8; 4198c2ecf20Sopenharmony_ci default: 4208c2ecf20Sopenharmony_ci return rate; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic irqreturn_t inno_hdmi_phy_rk3328_hardirq(int irq, void *dev_id) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = dev_id; 4278c2ecf20Sopenharmony_ci int intr_stat1, intr_stat2, intr_stat3; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci intr_stat1 = inno_read(inno, 0x04); 4308c2ecf20Sopenharmony_ci intr_stat2 = inno_read(inno, 0x06); 4318c2ecf20Sopenharmony_ci intr_stat3 = inno_read(inno, 0x08); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (intr_stat1) 4348c2ecf20Sopenharmony_ci inno_write(inno, 0x04, intr_stat1); 4358c2ecf20Sopenharmony_ci if (intr_stat2) 4368c2ecf20Sopenharmony_ci inno_write(inno, 0x06, intr_stat2); 4378c2ecf20Sopenharmony_ci if (intr_stat3) 4388c2ecf20Sopenharmony_ci inno_write(inno, 0x08, intr_stat3); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (intr_stat1 || intr_stat2 || intr_stat3) 4418c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic irqreturn_t inno_hdmi_phy_rk3328_irq(int irq, void *dev_id) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = dev_id; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); 4518c2ecf20Sopenharmony_ci usleep_range(10, 20); 4528c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_power_on(struct phy *phy) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = phy_get_drvdata(phy); 4608c2ecf20Sopenharmony_ci const struct post_pll_config *cfg = post_pll_cfg_table; 4618c2ecf20Sopenharmony_ci const struct phy_config *phy_cfg = inno->plat_data->phy_cfg_table; 4628c2ecf20Sopenharmony_ci unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, 4638c2ecf20Sopenharmony_ci inno->pixclock); 4648c2ecf20Sopenharmony_ci int ret; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!tmdsclock) { 4678c2ecf20Sopenharmony_ci dev_err(inno->dev, "TMDS clock is zero!\n"); 4688c2ecf20Sopenharmony_ci return -EINVAL; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (!inno->plat_data->ops->power_on) 4728c2ecf20Sopenharmony_ci return -EINVAL; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci for (; cfg->tmdsclock != 0; cfg++) 4758c2ecf20Sopenharmony_ci if (tmdsclock <= cfg->tmdsclock && 4768c2ecf20Sopenharmony_ci cfg->version & inno->chip_version) 4778c2ecf20Sopenharmony_ci break; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci for (; phy_cfg->tmdsclock != 0; phy_cfg++) 4808c2ecf20Sopenharmony_ci if (tmdsclock <= phy_cfg->tmdsclock) 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (cfg->tmdsclock == 0 || phy_cfg->tmdsclock == 0) 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "Inno HDMI PHY Power On\n"); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = clk_prepare_enable(inno->phyclk); 4898c2ecf20Sopenharmony_ci if (ret) 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = inno->plat_data->ops->power_on(inno, cfg, phy_cfg); 4938c2ecf20Sopenharmony_ci if (ret) { 4948c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->phyclk); 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return 0; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_power_off(struct phy *phy) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = phy_get_drvdata(phy); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci if (!inno->plat_data->ops->power_off) 5068c2ecf20Sopenharmony_ci return -EINVAL; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci inno->plat_data->ops->power_off(inno); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->phyclk); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "Inno HDMI PHY Power Off\n"); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic const struct phy_ops inno_hdmi_phy_ops = { 5188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5198c2ecf20Sopenharmony_ci .power_on = inno_hdmi_phy_power_on, 5208c2ecf20Sopenharmony_ci .power_off = inno_hdmi_phy_power_off, 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic const 5248c2ecf20Sopenharmony_cistruct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno, 5258c2ecf20Sopenharmony_ci unsigned long rate) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci const struct pre_pll_config *cfg = pre_pll_cfg_table; 5288c2ecf20Sopenharmony_ci unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci for (; cfg->pixclock != 0; cfg++) 5318c2ecf20Sopenharmony_ci if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock) 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (cfg->pixclock == 0) 5358c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return cfg; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3228_clk_is_prepared(struct clk_hw *hw) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 5438c2ecf20Sopenharmony_ci u8 status; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci status = inno_read(inno, 0xe0) & RK3228_PRE_PLL_POWER_DOWN; 5468c2ecf20Sopenharmony_ci return status ? 0 : 1; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3228_clk_prepare(struct clk_hw *hw) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic void inno_hdmi_phy_rk3228_clk_unprepare(struct clk_hw *hw) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 5628c2ecf20Sopenharmony_ci RK3228_PRE_PLL_POWER_DOWN); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic 5668c2ecf20Sopenharmony_ciunsigned long inno_hdmi_phy_rk3228_clk_recalc_rate(struct clk_hw *hw, 5678c2ecf20Sopenharmony_ci unsigned long parent_rate) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 5708c2ecf20Sopenharmony_ci u8 nd, no_a, no_b, no_d; 5718c2ecf20Sopenharmony_ci u64 vco; 5728c2ecf20Sopenharmony_ci u16 nf; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci nd = inno_read(inno, 0xe2) & RK3228_PRE_PLL_PRE_DIV_MASK; 5758c2ecf20Sopenharmony_ci nf = (inno_read(inno, 0xe2) & RK3228_PRE_PLL_FB_DIV_8_MASK) << 1; 5768c2ecf20Sopenharmony_ci nf |= inno_read(inno, 0xe3); 5778c2ecf20Sopenharmony_ci vco = parent_rate * nf; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (inno_read(inno, 0xe2) & RK3228_PCLK_VCO_DIV_5_MASK) { 5808c2ecf20Sopenharmony_ci do_div(vco, nd * 5); 5818c2ecf20Sopenharmony_ci } else { 5828c2ecf20Sopenharmony_ci no_a = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_A_MASK; 5838c2ecf20Sopenharmony_ci if (!no_a) 5848c2ecf20Sopenharmony_ci no_a = 1; 5858c2ecf20Sopenharmony_ci no_b = inno_read(inno, 0xe4) & RK3228_PRE_PLL_PCLK_DIV_B_MASK; 5868c2ecf20Sopenharmony_ci no_b >>= RK3228_PRE_PLL_PCLK_DIV_B_SHIFT; 5878c2ecf20Sopenharmony_ci no_b += 2; 5888c2ecf20Sopenharmony_ci no_d = inno_read(inno, 0xe5) & RK3228_PRE_PLL_PCLK_DIV_D_MASK; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci inno->pixclock = vco; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "%s rate %lu\n", __func__, inno->pixclock); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return vco; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw, 6018c2ecf20Sopenharmony_ci unsigned long rate, 6028c2ecf20Sopenharmony_ci unsigned long *parent_rate) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci const struct pre_pll_config *cfg = pre_pll_cfg_table; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci rate = (rate / 1000) * 1000; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci for (; cfg->pixclock != 0; cfg++) 6098c2ecf20Sopenharmony_ci if (cfg->pixclock == rate && !cfg->fracdiv) 6108c2ecf20Sopenharmony_ci break; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (cfg->pixclock == 0) 6138c2ecf20Sopenharmony_ci return -EINVAL; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return cfg->pixclock; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3228_clk_set_rate(struct clk_hw *hw, 6198c2ecf20Sopenharmony_ci unsigned long rate, 6208c2ecf20Sopenharmony_ci unsigned long parent_rate) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 6238c2ecf20Sopenharmony_ci const struct pre_pll_config *cfg = pre_pll_cfg_table; 6248c2ecf20Sopenharmony_ci unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); 6258c2ecf20Sopenharmony_ci u32 v; 6268c2ecf20Sopenharmony_ci int ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", 6298c2ecf20Sopenharmony_ci __func__, rate, tmdsclock); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); 6328c2ecf20Sopenharmony_ci if (IS_ERR(cfg)) 6338c2ecf20Sopenharmony_ci return PTR_ERR(cfg); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Power down PRE-PLL */ 6368c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 6378c2ecf20Sopenharmony_ci RK3228_PRE_PLL_POWER_DOWN); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe2, RK3228_PRE_PLL_FB_DIV_8_MASK | 6408c2ecf20Sopenharmony_ci RK3228_PCLK_VCO_DIV_5_MASK | 6418c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PRE_DIV_MASK, 6428c2ecf20Sopenharmony_ci RK3228_PRE_PLL_FB_DIV_8(cfg->fbdiv) | 6438c2ecf20Sopenharmony_ci RK3228_PCLK_VCO_DIV_5(cfg->vco_div_5_en) | 6448c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PRE_DIV(cfg->prediv)); 6458c2ecf20Sopenharmony_ci inno_write(inno, 0xe3, RK3228_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); 6468c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe4, RK3228_PRE_PLL_PCLK_DIV_B_MASK | 6478c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_A_MASK, 6488c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b) | 6498c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a)); 6508c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe5, RK3228_PRE_PLL_PCLK_DIV_C_MASK | 6518c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_D_MASK, 6528c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | 6538c2ecf20Sopenharmony_ci RK3228_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); 6548c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe6, RK3228_PRE_PLL_TMDSCLK_DIV_C_MASK | 6558c2ecf20Sopenharmony_ci RK3228_PRE_PLL_TMDSCLK_DIV_A_MASK | 6568c2ecf20Sopenharmony_ci RK3228_PRE_PLL_TMDSCLK_DIV_B_MASK, 6578c2ecf20Sopenharmony_ci RK3228_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | 6588c2ecf20Sopenharmony_ci RK3228_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | 6598c2ecf20Sopenharmony_ci RK3228_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Power up PRE-PLL */ 6628c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN, 0); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* Wait for Pre-PLL lock */ 6658c2ecf20Sopenharmony_ci ret = inno_poll(inno, 0xe8, v, v & RK3228_PRE_PLL_LOCK_STATUS, 6668c2ecf20Sopenharmony_ci 100, 100000); 6678c2ecf20Sopenharmony_ci if (ret) { 6688c2ecf20Sopenharmony_ci dev_err(inno->dev, "Pre-PLL locking failed\n"); 6698c2ecf20Sopenharmony_ci return ret; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci inno->pixclock = rate; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci} 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_cistatic const struct clk_ops inno_hdmi_phy_rk3228_clk_ops = { 6788c2ecf20Sopenharmony_ci .prepare = inno_hdmi_phy_rk3228_clk_prepare, 6798c2ecf20Sopenharmony_ci .unprepare = inno_hdmi_phy_rk3228_clk_unprepare, 6808c2ecf20Sopenharmony_ci .is_prepared = inno_hdmi_phy_rk3228_clk_is_prepared, 6818c2ecf20Sopenharmony_ci .recalc_rate = inno_hdmi_phy_rk3228_clk_recalc_rate, 6828c2ecf20Sopenharmony_ci .round_rate = inno_hdmi_phy_rk3228_clk_round_rate, 6838c2ecf20Sopenharmony_ci .set_rate = inno_hdmi_phy_rk3228_clk_set_rate, 6848c2ecf20Sopenharmony_ci}; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3328_clk_is_prepared(struct clk_hw *hw) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 6898c2ecf20Sopenharmony_ci u8 status; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci status = inno_read(inno, 0xa0) & RK3328_PRE_PLL_POWER_DOWN; 6928c2ecf20Sopenharmony_ci return status ? 0 : 1; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3328_clk_prepare(struct clk_hw *hw) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_cistatic void inno_hdmi_phy_rk3328_clk_unprepare(struct clk_hw *hw) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 7088c2ecf20Sopenharmony_ci RK3328_PRE_PLL_POWER_DOWN); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic 7128c2ecf20Sopenharmony_ciunsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct clk_hw *hw, 7138c2ecf20Sopenharmony_ci unsigned long parent_rate) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 7168c2ecf20Sopenharmony_ci unsigned long frac; 7178c2ecf20Sopenharmony_ci u8 nd, no_a, no_b, no_c, no_d; 7188c2ecf20Sopenharmony_ci u64 vco; 7198c2ecf20Sopenharmony_ci u16 nf; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK; 7228c2ecf20Sopenharmony_ci nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8); 7238c2ecf20Sopenharmony_ci nf |= inno_read(inno, 0xa3); 7248c2ecf20Sopenharmony_ci vco = parent_rate * nf; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) { 7278c2ecf20Sopenharmony_ci frac = inno_read(inno, 0xd3) | 7288c2ecf20Sopenharmony_ci (inno_read(inno, 0xd2) << 8) | 7298c2ecf20Sopenharmony_ci (inno_read(inno, 0xd1) << 16); 7308c2ecf20Sopenharmony_ci vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24)); 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) { 7348c2ecf20Sopenharmony_ci do_div(vco, nd * 5); 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK; 7378c2ecf20Sopenharmony_ci no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; 7388c2ecf20Sopenharmony_ci no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; 7398c2ecf20Sopenharmony_ci no_b += 2; 7408c2ecf20Sopenharmony_ci no_c = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_C_MASK; 7418c2ecf20Sopenharmony_ci no_c >>= RK3328_PRE_PLL_PCLK_DIV_C_SHIFT; 7428c2ecf20Sopenharmony_ci no_c = 1 << no_c; 7438c2ecf20Sopenharmony_ci no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "%s rate %lu vco %llu\n", 7518c2ecf20Sopenharmony_ci __func__, inno->pixclock, vco); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci return inno->pixclock; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, 7578c2ecf20Sopenharmony_ci unsigned long rate, 7588c2ecf20Sopenharmony_ci unsigned long *parent_rate) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci const struct pre_pll_config *cfg = pre_pll_cfg_table; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci rate = (rate / 1000) * 1000; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci for (; cfg->pixclock != 0; cfg++) 7658c2ecf20Sopenharmony_ci if (cfg->pixclock == rate) 7668c2ecf20Sopenharmony_ci break; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (cfg->pixclock == 0) 7698c2ecf20Sopenharmony_ci return -EINVAL; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return cfg->pixclock; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3328_clk_set_rate(struct clk_hw *hw, 7758c2ecf20Sopenharmony_ci unsigned long rate, 7768c2ecf20Sopenharmony_ci unsigned long parent_rate) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = to_inno_hdmi_phy(hw); 7798c2ecf20Sopenharmony_ci const struct pre_pll_config *cfg = pre_pll_cfg_table; 7808c2ecf20Sopenharmony_ci unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); 7818c2ecf20Sopenharmony_ci u32 val; 7828c2ecf20Sopenharmony_ci int ret; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci dev_dbg(inno->dev, "%s rate %lu tmdsclk %lu\n", 7858c2ecf20Sopenharmony_ci __func__, rate, tmdsclock); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); 7888c2ecf20Sopenharmony_ci if (IS_ERR(cfg)) 7898c2ecf20Sopenharmony_ci return PTR_ERR(cfg); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 7928c2ecf20Sopenharmony_ci RK3328_PRE_PLL_POWER_DOWN); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Configure pre-pll */ 7958c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, 7968c2ecf20Sopenharmony_ci RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); 7978c2ecf20Sopenharmony_ci inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; 8008c2ecf20Sopenharmony_ci if (!cfg->fracdiv) 8018c2ecf20Sopenharmony_ci val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE; 8028c2ecf20Sopenharmony_ci inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val); 8038c2ecf20Sopenharmony_ci inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); 8048c2ecf20Sopenharmony_ci inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) | 8058c2ecf20Sopenharmony_ci RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b)); 8068c2ecf20Sopenharmony_ci inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | 8078c2ecf20Sopenharmony_ci RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); 8088c2ecf20Sopenharmony_ci inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | 8098c2ecf20Sopenharmony_ci RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | 8108c2ecf20Sopenharmony_ci RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); 8118c2ecf20Sopenharmony_ci inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv)); 8128c2ecf20Sopenharmony_ci inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv)); 8138c2ecf20Sopenharmony_ci inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv)); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* Wait for Pre-PLL lock */ 8188c2ecf20Sopenharmony_ci ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS, 8198c2ecf20Sopenharmony_ci 1000, 10000); 8208c2ecf20Sopenharmony_ci if (ret) { 8218c2ecf20Sopenharmony_ci dev_err(inno->dev, "Pre-PLL locking failed\n"); 8228c2ecf20Sopenharmony_ci return ret; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci inno->pixclock = rate; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci return 0; 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic const struct clk_ops inno_hdmi_phy_rk3328_clk_ops = { 8318c2ecf20Sopenharmony_ci .prepare = inno_hdmi_phy_rk3328_clk_prepare, 8328c2ecf20Sopenharmony_ci .unprepare = inno_hdmi_phy_rk3328_clk_unprepare, 8338c2ecf20Sopenharmony_ci .is_prepared = inno_hdmi_phy_rk3328_clk_is_prepared, 8348c2ecf20Sopenharmony_ci .recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate, 8358c2ecf20Sopenharmony_ci .round_rate = inno_hdmi_phy_rk3328_clk_round_rate, 8368c2ecf20Sopenharmony_ci .set_rate = inno_hdmi_phy_rk3328_clk_set_rate, 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_clk_register(struct inno_hdmi_phy *inno) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct device *dev = inno->dev; 8428c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 8438c2ecf20Sopenharmony_ci struct clk_init_data init; 8448c2ecf20Sopenharmony_ci const char *parent_name; 8458c2ecf20Sopenharmony_ci int ret; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci parent_name = __clk_get_name(inno->refoclk); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 8508c2ecf20Sopenharmony_ci init.num_parents = 1; 8518c2ecf20Sopenharmony_ci init.flags = 0; 8528c2ecf20Sopenharmony_ci init.name = "pin_hd20_pclk"; 8538c2ecf20Sopenharmony_ci init.ops = inno->plat_data->clk_ops; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* optional override of the clock name */ 8568c2ecf20Sopenharmony_ci of_property_read_string(np, "clock-output-names", &init.name); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci inno->hw.init = &init; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci inno->phyclk = devm_clk_register(dev, &inno->hw); 8618c2ecf20Sopenharmony_ci if (IS_ERR(inno->phyclk)) { 8628c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->phyclk); 8638c2ecf20Sopenharmony_ci dev_err(dev, "failed to register clock: %d\n", ret); 8648c2ecf20Sopenharmony_ci return ret; 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci ret = of_clk_add_provider(np, of_clk_src_simple_get, inno->phyclk); 8688c2ecf20Sopenharmony_ci if (ret) { 8698c2ecf20Sopenharmony_ci dev_err(dev, "failed to register clock provider: %d\n", ret); 8708c2ecf20Sopenharmony_ci return ret; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci return 0; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3228_init(struct inno_hdmi_phy *inno) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci /* 8798c2ecf20Sopenharmony_ci * Use phy internal register control 8808c2ecf20Sopenharmony_ci * rxsense/poweron/pllpd/pdataen signal. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ci inno_write(inno, 0x01, RK3228_BYPASS_RXSENSE_EN | 8838c2ecf20Sopenharmony_ci RK3228_BYPASS_PWRON_EN | 8848c2ecf20Sopenharmony_ci RK3228_BYPASS_PLLPD_EN); 8858c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3228_BYPASS_PDATA_EN, 8868c2ecf20Sopenharmony_ci RK3228_BYPASS_PDATA_EN); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* manual power down post-PLL */ 8898c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xaa, RK3228_POST_PLL_CTRL_MANUAL, 8908c2ecf20Sopenharmony_ci RK3228_POST_PLL_CTRL_MANUAL); 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci inno->chip_version = 1; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int 8988c2ecf20Sopenharmony_ciinno_hdmi_phy_rk3228_power_on(struct inno_hdmi_phy *inno, 8998c2ecf20Sopenharmony_ci const struct post_pll_config *cfg, 9008c2ecf20Sopenharmony_ci const struct phy_config *phy_cfg) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int ret; 9038c2ecf20Sopenharmony_ci u32 v; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, 9068c2ecf20Sopenharmony_ci RK3228_PDATAEN_DISABLE); 9078c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | 9088c2ecf20Sopenharmony_ci RK3228_POST_PLL_POWER_DOWN, 9098c2ecf20Sopenharmony_ci RK3228_PRE_PLL_POWER_DOWN | 9108c2ecf20Sopenharmony_ci RK3228_POST_PLL_POWER_DOWN); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Post-PLL update */ 9138c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe9, RK3228_POST_PLL_PRE_DIV_MASK, 9148c2ecf20Sopenharmony_ci RK3228_POST_PLL_PRE_DIV(cfg->prediv)); 9158c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xeb, RK3228_POST_PLL_FB_DIV_8_MASK, 9168c2ecf20Sopenharmony_ci RK3228_POST_PLL_FB_DIV_8(cfg->fbdiv)); 9178c2ecf20Sopenharmony_ci inno_write(inno, 0xea, RK3228_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci if (cfg->postdiv == 1) { 9208c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, 9218c2ecf20Sopenharmony_ci 0); 9228c2ecf20Sopenharmony_ci } else { 9238c2ecf20Sopenharmony_ci int div = cfg->postdiv / 2 - 1; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe9, RK3228_POST_PLL_POST_DIV_ENABLE, 9268c2ecf20Sopenharmony_ci RK3228_POST_PLL_POST_DIV_ENABLE); 9278c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xeb, RK3228_POST_PLL_POST_DIV_MASK, 9288c2ecf20Sopenharmony_ci RK3228_POST_PLL_POST_DIV(div)); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci for (v = 0; v < 4; v++) 9328c2ecf20Sopenharmony_ci inno_write(inno, 0xef + v, phy_cfg->regs[v]); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_PRE_PLL_POWER_DOWN | 9358c2ecf20Sopenharmony_ci RK3228_POST_PLL_POWER_DOWN, 0); 9368c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, 9378c2ecf20Sopenharmony_ci RK3228_BANDGAP_ENABLE); 9388c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, 9398c2ecf20Sopenharmony_ci RK3228_TMDS_DRIVER_ENABLE); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* Wait for post PLL lock */ 9428c2ecf20Sopenharmony_ci ret = inno_poll(inno, 0xeb, v, v & RK3228_POST_PLL_LOCK_STATUS, 9438c2ecf20Sopenharmony_ci 100, 100000); 9448c2ecf20Sopenharmony_ci if (ret) { 9458c2ecf20Sopenharmony_ci dev_err(inno->dev, "Post-PLL locking failed\n"); 9468c2ecf20Sopenharmony_ci return ret; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (cfg->tmdsclock > 340000000) 9508c2ecf20Sopenharmony_ci msleep(100); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3228_PDATAEN_DISABLE, 0); 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic void inno_hdmi_phy_rk3228_power_off(struct inno_hdmi_phy *inno) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe1, RK3228_TMDS_DRIVER_ENABLE, 0); 9598c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe1, RK3228_BANDGAP_ENABLE, 0); 9608c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xe0, RK3228_POST_PLL_POWER_DOWN, 9618c2ecf20Sopenharmony_ci RK3228_POST_PLL_POWER_DOWN); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic const struct inno_hdmi_phy_ops rk3228_hdmi_phy_ops = { 9658c2ecf20Sopenharmony_ci .init = inno_hdmi_phy_rk3228_init, 9668c2ecf20Sopenharmony_ci .power_on = inno_hdmi_phy_rk3228_power_on, 9678c2ecf20Sopenharmony_ci .power_off = inno_hdmi_phy_rk3228_power_off, 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_rk3328_init(struct inno_hdmi_phy *inno) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct nvmem_cell *cell; 9738c2ecf20Sopenharmony_ci unsigned char *efuse_buf; 9748c2ecf20Sopenharmony_ci size_t len; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* 9778c2ecf20Sopenharmony_ci * Use phy internal register control 9788c2ecf20Sopenharmony_ci * rxsense/poweron/pllpd/pdataen signal. 9798c2ecf20Sopenharmony_ci */ 9808c2ecf20Sopenharmony_ci inno_write(inno, 0x01, RK3328_BYPASS_RXSENSE_EN | 9818c2ecf20Sopenharmony_ci RK3328_BYPASS_POWERON_EN | 9828c2ecf20Sopenharmony_ci RK3328_BYPASS_PLLPD_EN); 9838c2ecf20Sopenharmony_ci inno_write(inno, 0x02, RK3328_INT_POL_HIGH | RK3328_BYPASS_PDATA_EN | 9848c2ecf20Sopenharmony_ci RK3328_PDATA_EN); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* Disable phy irq */ 9878c2ecf20Sopenharmony_ci inno_write(inno, 0x05, 0); 9888c2ecf20Sopenharmony_ci inno_write(inno, 0x07, 0); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci /* try to read the chip-version */ 9918c2ecf20Sopenharmony_ci inno->chip_version = 1; 9928c2ecf20Sopenharmony_ci cell = nvmem_cell_get(inno->dev, "cpu-version"); 9938c2ecf20Sopenharmony_ci if (IS_ERR(cell)) { 9948c2ecf20Sopenharmony_ci if (PTR_ERR(cell) == -EPROBE_DEFER) 9958c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci return 0; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci efuse_buf = nvmem_cell_read(cell, &len); 10018c2ecf20Sopenharmony_ci nvmem_cell_put(cell); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (IS_ERR(efuse_buf)) 10048c2ecf20Sopenharmony_ci return 0; 10058c2ecf20Sopenharmony_ci if (len == 1) 10068c2ecf20Sopenharmony_ci inno->chip_version = efuse_buf[0] + 1; 10078c2ecf20Sopenharmony_ci kfree(efuse_buf); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci} 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_cistatic int 10138c2ecf20Sopenharmony_ciinno_hdmi_phy_rk3328_power_on(struct inno_hdmi_phy *inno, 10148c2ecf20Sopenharmony_ci const struct post_pll_config *cfg, 10158c2ecf20Sopenharmony_ci const struct phy_config *phy_cfg) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci int ret; 10188c2ecf20Sopenharmony_ci u32 v; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); 10218c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 10228c2ecf20Sopenharmony_ci RK3328_POST_PLL_POWER_DOWN); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); 10258c2ecf20Sopenharmony_ci if (cfg->postdiv == 1) { 10268c2ecf20Sopenharmony_ci inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | 10278c2ecf20Sopenharmony_ci RK3328_POST_PLL_PRE_DIV(cfg->prediv)); 10288c2ecf20Sopenharmony_ci inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | 10298c2ecf20Sopenharmony_ci RK3328_POST_PLL_POWER_DOWN); 10308c2ecf20Sopenharmony_ci } else { 10318c2ecf20Sopenharmony_ci v = (cfg->postdiv / 2) - 1; 10328c2ecf20Sopenharmony_ci v &= RK3328_POST_PLL_POST_DIV_MASK; 10338c2ecf20Sopenharmony_ci inno_write(inno, 0xad, v); 10348c2ecf20Sopenharmony_ci inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | 10358c2ecf20Sopenharmony_ci RK3328_POST_PLL_PRE_DIV(cfg->prediv)); 10368c2ecf20Sopenharmony_ci inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | 10378c2ecf20Sopenharmony_ci RK3328_POST_PLL_REFCLK_SEL_TMDS | 10388c2ecf20Sopenharmony_ci RK3328_POST_PLL_POWER_DOWN); 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci for (v = 0; v < 14; v++) 10428c2ecf20Sopenharmony_ci inno_write(inno, 0xb5 + v, phy_cfg->regs[v]); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* set ESD detection threshold for TMDS CLK, D2, D1 and D0 */ 10458c2ecf20Sopenharmony_ci for (v = 0; v < 4; v++) 10468c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xc8 + v, RK3328_ESD_DETECT_MASK, 10478c2ecf20Sopenharmony_ci RK3328_ESD_DETECT_340MV); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (phy_cfg->tmdsclock > 340000000) { 10508c2ecf20Sopenharmony_ci /* Set termination resistor to 100ohm */ 10518c2ecf20Sopenharmony_ci v = clk_get_rate(inno->sysclk) / 100000; 10528c2ecf20Sopenharmony_ci inno_write(inno, 0xc5, RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(v) 10538c2ecf20Sopenharmony_ci | RK3328_BYPASS_TERM_RESISTOR_CALIB); 10548c2ecf20Sopenharmony_ci inno_write(inno, 0xc6, RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(v)); 10558c2ecf20Sopenharmony_ci inno_write(inno, 0xc7, RK3328_TERM_RESISTOR_100); 10568c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xc5, 10578c2ecf20Sopenharmony_ci RK3328_BYPASS_TERM_RESISTOR_CALIB, 0); 10588c2ecf20Sopenharmony_ci } else { 10598c2ecf20Sopenharmony_ci inno_write(inno, 0xc5, RK3328_BYPASS_TERM_RESISTOR_CALIB); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci /* clk termination resistor is 50ohm (parallel resistors) */ 10628c2ecf20Sopenharmony_ci if (phy_cfg->tmdsclock > 165000000) 10638c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xc8, 10648c2ecf20Sopenharmony_ci RK3328_TMDS_TERM_RESIST_MASK, 10658c2ecf20Sopenharmony_ci RK3328_TMDS_TERM_RESIST_75 | 10668c2ecf20Sopenharmony_ci RK3328_TMDS_TERM_RESIST_150); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* data termination resistor for D2, D1 and D0 is 150ohm */ 10698c2ecf20Sopenharmony_ci for (v = 0; v < 3; v++) 10708c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xc9 + v, 10718c2ecf20Sopenharmony_ci RK3328_TMDS_TERM_RESIST_MASK, 10728c2ecf20Sopenharmony_ci RK3328_TMDS_TERM_RESIST_150); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 0); 10768c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 10778c2ecf20Sopenharmony_ci RK3328_BANDGAP_ENABLE); 10788c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 10798c2ecf20Sopenharmony_ci RK3328_TMDS_DRIVER_ENABLE); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Wait for post PLL lock */ 10828c2ecf20Sopenharmony_ci ret = inno_poll(inno, 0xaf, v, v & RK3328_POST_PLL_LOCK_STATUS, 10838c2ecf20Sopenharmony_ci 1000, 10000); 10848c2ecf20Sopenharmony_ci if (ret) { 10858c2ecf20Sopenharmony_ci dev_err(inno->dev, "Post-PLL locking failed\n"); 10868c2ecf20Sopenharmony_ci return ret; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (phy_cfg->tmdsclock > 340000000) 10908c2ecf20Sopenharmony_ci msleep(100); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* Enable PHY IRQ */ 10958c2ecf20Sopenharmony_ci inno_write(inno, 0x05, RK3328_INT_TMDS_CLK(RK3328_INT_VSS_AGND_ESD_DET) 10968c2ecf20Sopenharmony_ci | RK3328_INT_TMDS_D2(RK3328_INT_VSS_AGND_ESD_DET)); 10978c2ecf20Sopenharmony_ci inno_write(inno, 0x07, RK3328_INT_TMDS_D1(RK3328_INT_VSS_AGND_ESD_DET) 10988c2ecf20Sopenharmony_ci | RK3328_INT_TMDS_D0(RK3328_INT_VSS_AGND_ESD_DET)); 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic void inno_hdmi_phy_rk3328_power_off(struct inno_hdmi_phy *inno) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 0); 11058c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 0); 11068c2ecf20Sopenharmony_ci inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 11078c2ecf20Sopenharmony_ci RK3328_POST_PLL_POWER_DOWN); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* Disable PHY IRQ */ 11108c2ecf20Sopenharmony_ci inno_write(inno, 0x05, 0); 11118c2ecf20Sopenharmony_ci inno_write(inno, 0x07, 0); 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic const struct inno_hdmi_phy_ops rk3328_hdmi_phy_ops = { 11158c2ecf20Sopenharmony_ci .init = inno_hdmi_phy_rk3328_init, 11168c2ecf20Sopenharmony_ci .power_on = inno_hdmi_phy_rk3328_power_on, 11178c2ecf20Sopenharmony_ci .power_off = inno_hdmi_phy_rk3328_power_off, 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic const struct inno_hdmi_phy_drv_data rk3228_hdmi_phy_drv_data = { 11218c2ecf20Sopenharmony_ci .ops = &rk3228_hdmi_phy_ops, 11228c2ecf20Sopenharmony_ci .clk_ops = &inno_hdmi_phy_rk3228_clk_ops, 11238c2ecf20Sopenharmony_ci .phy_cfg_table = rk3228_phy_cfg, 11248c2ecf20Sopenharmony_ci}; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic const struct inno_hdmi_phy_drv_data rk3328_hdmi_phy_drv_data = { 11278c2ecf20Sopenharmony_ci .ops = &rk3328_hdmi_phy_ops, 11288c2ecf20Sopenharmony_ci .clk_ops = &inno_hdmi_phy_rk3328_clk_ops, 11298c2ecf20Sopenharmony_ci .phy_cfg_table = rk3328_phy_cfg, 11308c2ecf20Sopenharmony_ci}; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic const struct regmap_config inno_hdmi_phy_regmap_config = { 11338c2ecf20Sopenharmony_ci .reg_bits = 32, 11348c2ecf20Sopenharmony_ci .val_bits = 32, 11358c2ecf20Sopenharmony_ci .reg_stride = 4, 11368c2ecf20Sopenharmony_ci .max_register = 0x400, 11378c2ecf20Sopenharmony_ci}; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic void inno_hdmi_phy_action(void *data) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno = data; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->refpclk); 11448c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->sysclk); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_probe(struct platform_device *pdev) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct inno_hdmi_phy *inno; 11508c2ecf20Sopenharmony_ci struct phy_provider *phy_provider; 11518c2ecf20Sopenharmony_ci struct resource *res; 11528c2ecf20Sopenharmony_ci void __iomem *regs; 11538c2ecf20Sopenharmony_ci int ret; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci inno = devm_kzalloc(&pdev->dev, sizeof(*inno), GFP_KERNEL); 11568c2ecf20Sopenharmony_ci if (!inno) 11578c2ecf20Sopenharmony_ci return -ENOMEM; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci inno->dev = &pdev->dev; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci inno->plat_data = of_device_get_match_data(inno->dev); 11628c2ecf20Sopenharmony_ci if (!inno->plat_data || !inno->plat_data->ops) 11638c2ecf20Sopenharmony_ci return -EINVAL; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 11668c2ecf20Sopenharmony_ci regs = devm_ioremap_resource(inno->dev, res); 11678c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 11688c2ecf20Sopenharmony_ci return PTR_ERR(regs); 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci inno->sysclk = devm_clk_get(inno->dev, "sysclk"); 11718c2ecf20Sopenharmony_ci if (IS_ERR(inno->sysclk)) { 11728c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->sysclk); 11738c2ecf20Sopenharmony_ci dev_err(inno->dev, "failed to get sysclk: %d\n", ret); 11748c2ecf20Sopenharmony_ci return ret; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci inno->refpclk = devm_clk_get(inno->dev, "refpclk"); 11788c2ecf20Sopenharmony_ci if (IS_ERR(inno->refpclk)) { 11798c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->refpclk); 11808c2ecf20Sopenharmony_ci dev_err(inno->dev, "failed to get ref clock: %d\n", ret); 11818c2ecf20Sopenharmony_ci return ret; 11828c2ecf20Sopenharmony_ci } 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci inno->refoclk = devm_clk_get(inno->dev, "refoclk"); 11858c2ecf20Sopenharmony_ci if (IS_ERR(inno->refoclk)) { 11868c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->refoclk); 11878c2ecf20Sopenharmony_ci dev_err(inno->dev, "failed to get oscillator-ref clock: %d\n", 11888c2ecf20Sopenharmony_ci ret); 11898c2ecf20Sopenharmony_ci return ret; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci ret = clk_prepare_enable(inno->sysclk); 11938c2ecf20Sopenharmony_ci if (ret) { 11948c2ecf20Sopenharmony_ci dev_err(inno->dev, "Cannot enable inno phy sysclk: %d\n", ret); 11958c2ecf20Sopenharmony_ci return ret; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* 11998c2ecf20Sopenharmony_ci * Refpclk needs to be on, on at least the rk3328 for still 12008c2ecf20Sopenharmony_ci * unknown reasons. 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_ci ret = clk_prepare_enable(inno->refpclk); 12038c2ecf20Sopenharmony_ci if (ret) { 12048c2ecf20Sopenharmony_ci dev_err(inno->dev, "failed to enable refpclk\n"); 12058c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->sysclk); 12068c2ecf20Sopenharmony_ci return ret; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(inno->dev, inno_hdmi_phy_action, 12108c2ecf20Sopenharmony_ci inno); 12118c2ecf20Sopenharmony_ci if (ret) 12128c2ecf20Sopenharmony_ci return ret; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci inno->regmap = devm_regmap_init_mmio(inno->dev, regs, 12158c2ecf20Sopenharmony_ci &inno_hdmi_phy_regmap_config); 12168c2ecf20Sopenharmony_ci if (IS_ERR(inno->regmap)) 12178c2ecf20Sopenharmony_ci return PTR_ERR(inno->regmap); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci /* only the newer rk3328 hdmiphy has an interrupt */ 12208c2ecf20Sopenharmony_ci inno->irq = platform_get_irq(pdev, 0); 12218c2ecf20Sopenharmony_ci if (inno->irq > 0) { 12228c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(inno->dev, inno->irq, 12238c2ecf20Sopenharmony_ci inno_hdmi_phy_rk3328_hardirq, 12248c2ecf20Sopenharmony_ci inno_hdmi_phy_rk3328_irq, 12258c2ecf20Sopenharmony_ci IRQF_SHARED, 12268c2ecf20Sopenharmony_ci dev_name(inno->dev), inno); 12278c2ecf20Sopenharmony_ci if (ret) 12288c2ecf20Sopenharmony_ci return ret; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci inno->phy = devm_phy_create(inno->dev, NULL, &inno_hdmi_phy_ops); 12328c2ecf20Sopenharmony_ci if (IS_ERR(inno->phy)) { 12338c2ecf20Sopenharmony_ci dev_err(inno->dev, "failed to create HDMI PHY\n"); 12348c2ecf20Sopenharmony_ci return PTR_ERR(inno->phy); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci phy_set_drvdata(inno->phy, inno); 12388c2ecf20Sopenharmony_ci phy_set_bus_width(inno->phy, 8); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (inno->plat_data->ops->init) { 12418c2ecf20Sopenharmony_ci ret = inno->plat_data->ops->init(inno); 12428c2ecf20Sopenharmony_ci if (ret) 12438c2ecf20Sopenharmony_ci return ret; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci ret = inno_hdmi_phy_clk_register(inno); 12478c2ecf20Sopenharmony_ci if (ret) 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci phy_provider = devm_of_phy_provider_register(inno->dev, 12518c2ecf20Sopenharmony_ci of_phy_simple_xlate); 12528c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(phy_provider); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic int inno_hdmi_phy_remove(struct platform_device *pdev) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci of_clk_del_provider(pdev->dev.of_node); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic const struct of_device_id inno_hdmi_phy_of_match[] = { 12638c2ecf20Sopenharmony_ci { 12648c2ecf20Sopenharmony_ci .compatible = "rockchip,rk3228-hdmi-phy", 12658c2ecf20Sopenharmony_ci .data = &rk3228_hdmi_phy_drv_data 12668c2ecf20Sopenharmony_ci }, { 12678c2ecf20Sopenharmony_ci .compatible = "rockchip,rk3328-hdmi-phy", 12688c2ecf20Sopenharmony_ci .data = &rk3328_hdmi_phy_drv_data 12698c2ecf20Sopenharmony_ci }, { /* sentinel */ } 12708c2ecf20Sopenharmony_ci}; 12718c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic struct platform_driver inno_hdmi_phy_driver = { 12748c2ecf20Sopenharmony_ci .probe = inno_hdmi_phy_probe, 12758c2ecf20Sopenharmony_ci .remove = inno_hdmi_phy_remove, 12768c2ecf20Sopenharmony_ci .driver = { 12778c2ecf20Sopenharmony_ci .name = "inno-hdmi-phy", 12788c2ecf20Sopenharmony_ci .of_match_table = inno_hdmi_phy_of_match, 12798c2ecf20Sopenharmony_ci }, 12808c2ecf20Sopenharmony_ci}; 12818c2ecf20Sopenharmony_cimodule_platform_driver(inno_hdmi_phy_driver); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ciMODULE_AUTHOR("Zheng Yang <zhengyang@rock-chips.com>"); 12848c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Innosilion HDMI 2.0 Transmitter PHY Driver"); 12858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1286