18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * camss-csiphy-3ph-1-0.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Qualcomm MSM Camera Subsystem - CSIPHY Module 3phase v1.0 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. 88c2ecf20Sopenharmony_ci * Copyright (C) 2016-2018 Linaro Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "camss-csiphy.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/io.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG1(n) (0x000 + 0x100 * (n)) 188c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG (BIT(7) | BIT(6)) 198c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG2(n) (0x004 + 0x100 * (n)) 208c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG2_LP_REC_EN_INT BIT(3) 218c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG3(n) (0x008 + 0x100 * (n)) 228c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG4(n) (0x00c + 0x100 * (n)) 238c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS 0xa4 248c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG5(n) (0x010 + 0x100 * (n)) 258c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG5_T_HS_DTERM 0x02 268c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG5_HS_REC_EQ_FQ_INT 0x50 278c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_TEST_IMP(n) (0x01c + 0x100 * (n)) 288c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_TEST_IMP_HS_TERM_IMP 0xa 298c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_MISC1(n) (0x028 + 0x100 * (n)) 308c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_MISC1_IS_CLKLANE BIT(2) 318c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG6(n) (0x02c + 0x100 * (n)) 328c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG6_SWI_FORCE_INIT_EXIT BIT(0) 338c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG7(n) (0x030 + 0x100 * (n)) 348c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG7_SWI_T_INIT 0x2 358c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG8(n) (0x034 + 0x100 * (n)) 368c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG8_SWI_SKIP_WAKEUP BIT(0) 378c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG8_SKEW_FILTER_ENABLE BIT(1) 388c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG9(n) (0x038 + 0x100 * (n)) 398c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CFG9_SWI_T_WAKEUP 0x1 408c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CSI_LANE_CTRL15(n) (0x03c + 0x100 * (n)) 418c2ecf20Sopenharmony_ci#define CSIPHY_3PH_LNn_CSI_LANE_CTRL15_SWI_SOT_SYMBOL 0xb8 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(n) (0x800 + 0x4 * (n)) 448c2ecf20Sopenharmony_ci#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B BIT(0) 458c2ecf20Sopenharmony_ci#define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID BIT(1) 468c2ecf20Sopenharmony_ci#define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(n) (0x8b0 + 0x4 * (n)) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void csiphy_hw_version_read(struct csiphy_device *csiphy, 498c2ecf20Sopenharmony_ci struct device *dev) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci u32 hw_version; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci writel(CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID, 548c2ecf20Sopenharmony_ci csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6)); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci hw_version = readl_relaxed(csiphy->base + 578c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(12)); 588c2ecf20Sopenharmony_ci hw_version |= readl_relaxed(csiphy->base + 598c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(13)) << 8; 608c2ecf20Sopenharmony_ci hw_version |= readl_relaxed(csiphy->base + 618c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(14)) << 16; 628c2ecf20Sopenharmony_ci hw_version |= readl_relaxed(csiphy->base + 638c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(15)) << 24; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci dev_err(dev, "CSIPHY 3PH HW Version = 0x%08x\n", hw_version); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * csiphy_reset - Perform software reset on CSIPHY module 708c2ecf20Sopenharmony_ci * @csiphy: CSIPHY device 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cistatic void csiphy_reset(struct csiphy_device *csiphy) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci writel_relaxed(0x1, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0)); 758c2ecf20Sopenharmony_ci usleep_range(5000, 8000); 768c2ecf20Sopenharmony_ci writel_relaxed(0x0, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic irqreturn_t csiphy_isr(int irq, void *dev) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct csiphy_device *csiphy = dev; 828c2ecf20Sopenharmony_ci int i; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci for (i = 0; i < 11; i++) { 858c2ecf20Sopenharmony_ci int c = i + 22; 868c2ecf20Sopenharmony_ci u8 val = readl_relaxed(csiphy->base + 878c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(i)); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + 908c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(c)); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci writel_relaxed(0x1, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(10)); 948c2ecf20Sopenharmony_ci writel_relaxed(0x0, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(10)); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci for (i = 22; i < 33; i++) 978c2ecf20Sopenharmony_ci writel_relaxed(0x0, csiphy->base + 988c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(i)); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * csiphy_settle_cnt_calc - Calculate settle count value 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Helper function to calculate settle count value. This is 1078c2ecf20Sopenharmony_ci * based on the CSI2 T_hs_settle parameter which in turn 1088c2ecf20Sopenharmony_ci * is calculated based on the CSI2 transmitter pixel clock 1098c2ecf20Sopenharmony_ci * frequency. 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * Return settle count value or 0 if the CSI2 pixel clock 1128c2ecf20Sopenharmony_ci * frequency is not available 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_cistatic u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, 1158c2ecf20Sopenharmony_ci u32 timer_clk_rate) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u32 mipi_clock; /* Hz */ 1188c2ecf20Sopenharmony_ci u32 ui; /* ps */ 1198c2ecf20Sopenharmony_ci u32 timer_period; /* ps */ 1208c2ecf20Sopenharmony_ci u32 t_hs_prepare_max; /* ps */ 1218c2ecf20Sopenharmony_ci u32 t_hs_settle; /* ps */ 1228c2ecf20Sopenharmony_ci u8 settle_cnt; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci mipi_clock = pixel_clock * bpp / (2 * num_lanes); 1258c2ecf20Sopenharmony_ci ui = div_u64(1000000000000LL, mipi_clock); 1268c2ecf20Sopenharmony_ci ui /= 2; 1278c2ecf20Sopenharmony_ci t_hs_prepare_max = 85000 + 6 * ui; 1288c2ecf20Sopenharmony_ci t_hs_settle = t_hs_prepare_max; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci timer_period = div_u64(1000000000000LL, timer_clk_rate); 1318c2ecf20Sopenharmony_ci settle_cnt = t_hs_settle / timer_period - 6; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return settle_cnt; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void csiphy_lanes_enable(struct csiphy_device *csiphy, 1378c2ecf20Sopenharmony_ci struct csiphy_config *cfg, 1388c2ecf20Sopenharmony_ci u32 pixel_clock, u8 bpp, u8 lane_mask) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; 1418c2ecf20Sopenharmony_ci u8 settle_cnt; 1428c2ecf20Sopenharmony_ci u8 val, l = 0; 1438c2ecf20Sopenharmony_ci int i; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data, 1468c2ecf20Sopenharmony_ci csiphy->timer_clk_rate); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci val = BIT(c->clk.pos); 1498c2ecf20Sopenharmony_ci for (i = 0; i < c->num_data; i++) 1508c2ecf20Sopenharmony_ci val |= BIT(c->data[i].pos * 2); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5)); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B; 1558c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6)); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci for (i = 0; i <= c->num_data; i++) { 1588c2ecf20Sopenharmony_ci if (i == c->num_data) 1598c2ecf20Sopenharmony_ci l = 7; 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci l = c->data[i].pos * 2; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG; 1648c2ecf20Sopenharmony_ci val |= 0x17; 1658c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l)); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG2_LP_REC_EN_INT; 1688c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG2(l)); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci val = settle_cnt; 1718c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG3(l)); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG5_T_HS_DTERM | 1748c2ecf20Sopenharmony_ci CSIPHY_3PH_LNn_CFG5_HS_REC_EQ_FQ_INT; 1758c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG5(l)); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG6_SWI_FORCE_INIT_EXIT; 1788c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG6(l)); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG7_SWI_T_INIT; 1818c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG7(l)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG8_SWI_SKIP_WAKEUP | 1848c2ecf20Sopenharmony_ci CSIPHY_3PH_LNn_CFG8_SKEW_FILTER_ENABLE; 1858c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG8(l)); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG9_SWI_T_WAKEUP; 1888c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG9(l)); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_TEST_IMP_HS_TERM_IMP; 1918c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_TEST_IMP(l)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CSI_LANE_CTRL15_SWI_SOT_SYMBOL; 1948c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + 1958c2ecf20Sopenharmony_ci CSIPHY_3PH_LNn_CSI_LANE_CTRL15(l)); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG1_SWI_REC_DLY_PRG; 1998c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG1(l)); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_CFG4_T_HS_CLK_MISS; 2028c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_CFG4(l)); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE; 2058c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_MISC1(l)); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci val = 0xff; 2088c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(11)); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci val = 0xff; 2118c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(12)); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci val = 0xfb; 2148c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(13)); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci val = 0xff; 2178c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(14)); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci val = 0x7f; 2208c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(15)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci val = 0xff; 2238c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(16)); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci val = 0xff; 2268c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(17)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci val = 0xef; 2298c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(18)); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci val = 0xff; 2328c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(19)); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci val = 0xff; 2358c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(20)); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci val = 0xff; 2388c2ecf20Sopenharmony_ci writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(21)); 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void csiphy_lanes_disable(struct csiphy_device *csiphy, 2428c2ecf20Sopenharmony_ci struct csiphy_config *cfg) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci writel_relaxed(0, csiphy->base + 2458c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5)); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci writel_relaxed(0, csiphy->base + 2488c2ecf20Sopenharmony_ci CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6)); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciconst struct csiphy_hw_ops csiphy_ops_3ph_1_0 = { 2528c2ecf20Sopenharmony_ci .hw_version_read = csiphy_hw_version_read, 2538c2ecf20Sopenharmony_ci .reset = csiphy_reset, 2548c2ecf20Sopenharmony_ci .lanes_enable = csiphy_lanes_enable, 2558c2ecf20Sopenharmony_ci .lanes_disable = csiphy_lanes_disable, 2568c2ecf20Sopenharmony_ci .isr = csiphy_isr, 2578c2ecf20Sopenharmony_ci}; 258