Home | History | Annotate | Download | only in mach-omap2
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * TI PIPE3 PHY
      4  *
      5  * (C) Copyright 2013
      6  * Texas Instruments, <www.ti.com>
      7  */
      8 
      9 #include <common.h>
     10 #include <sata.h>
     11 #include <asm/arch/clock.h>
     12 #include <asm/arch/sys_proto.h>
     13 #include <asm/io.h>
     14 #include <linux/errno.h>
     15 #include "pipe3-phy.h"
     16 
     17 /* PLLCTRL Registers */
     18 #define PLL_STATUS              0x00000004
     19 #define PLL_GO                  0x00000008
     20 #define PLL_CONFIGURATION1      0x0000000C
     21 #define PLL_CONFIGURATION2      0x00000010
     22 #define PLL_CONFIGURATION3      0x00000014
     23 #define PLL_CONFIGURATION4      0x00000020
     24 
     25 #define PLL_REGM_MASK           0x001FFE00
     26 #define PLL_REGM_SHIFT          9
     27 #define PLL_REGM_F_MASK         0x0003FFFF
     28 #define PLL_REGM_F_SHIFT        0
     29 #define PLL_REGN_MASK           0x000001FE
     30 #define PLL_REGN_SHIFT          1
     31 #define PLL_SELFREQDCO_MASK     0x0000000E
     32 #define PLL_SELFREQDCO_SHIFT    1
     33 #define PLL_SD_MASK             0x0003FC00
     34 #define PLL_SD_SHIFT            10
     35 #define SET_PLL_GO              0x1
     36 #define PLL_TICOPWDN            BIT(16)
     37 #define PLL_LDOPWDN             BIT(15)
     38 #define PLL_LOCK                0x2
     39 #define PLL_IDLE                0x1
     40 
     41 /* PHY POWER CONTROL Register */
     42 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK         0x003FC000
     43 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT        0xE
     44 
     45 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK        0xFFC00000
     46 #define OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT       0x16
     47 
     48 #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON       0x3
     49 #define OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF      0x0
     50 
     51 
     52 #define PLL_IDLE_TIME   100     /* in milliseconds */
     53 #define PLL_LOCK_TIME   100     /* in milliseconds */
     54 
     55 static inline u32 omap_pipe3_readl(void __iomem *addr, unsigned offset)
     56 {
     57 	return __raw_readl(addr + offset);
     58 }
     59 
     60 static inline void omap_pipe3_writel(void __iomem *addr, unsigned offset,
     61 		u32 data)
     62 {
     63 	__raw_writel(data, addr + offset);
     64 }
     65 
     66 static struct pipe3_dpll_params *omap_pipe3_get_dpll_params(struct omap_pipe3
     67 									*pipe3)
     68 {
     69 	u32 rate;
     70 	struct pipe3_dpll_map *dpll_map = pipe3->dpll_map;
     71 
     72 	rate = get_sys_clk_freq();
     73 
     74 	for (; dpll_map->rate; dpll_map++) {
     75 		if (rate == dpll_map->rate)
     76 			return &dpll_map->params;
     77 	}
     78 
     79 	printf("%s: No DPLL configuration for %u Hz SYS CLK\n",
     80 	       __func__, rate);
     81 	return NULL;
     82 }
     83 
     84 
     85 static int omap_pipe3_wait_lock(struct omap_pipe3 *phy)
     86 {
     87 	u32 val;
     88 	int timeout = PLL_LOCK_TIME;
     89 
     90 	do {
     91 		mdelay(1);
     92 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
     93 		if (val & PLL_LOCK)
     94 			break;
     95 	} while (--timeout);
     96 
     97 	if (!(val & PLL_LOCK)) {
     98 		printf("%s: DPLL failed to lock\n", __func__);
     99 		return -EBUSY;
    100 	}
    101 
    102 	return 0;
    103 }
    104 
    105 static int omap_pipe3_dpll_program(struct omap_pipe3 *phy)
    106 {
    107 	u32                     val;
    108 	struct pipe3_dpll_params *dpll_params;
    109 
    110 	dpll_params = omap_pipe3_get_dpll_params(phy);
    111 	if (!dpll_params) {
    112 		printf("%s: Invalid DPLL parameters\n", __func__);
    113 		return -EINVAL;
    114 	}
    115 
    116 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
    117 	val &= ~PLL_REGN_MASK;
    118 	val |= dpll_params->n << PLL_REGN_SHIFT;
    119 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
    120 
    121 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
    122 	val &= ~PLL_SELFREQDCO_MASK;
    123 	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT;
    124 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
    125 
    126 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1);
    127 	val &= ~PLL_REGM_MASK;
    128 	val |= dpll_params->m << PLL_REGM_SHIFT;
    129 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val);
    130 
    131 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4);
    132 	val &= ~PLL_REGM_F_MASK;
    133 	val |= dpll_params->mf << PLL_REGM_F_SHIFT;
    134 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val);
    135 
    136 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3);
    137 	val &= ~PLL_SD_MASK;
    138 	val |= dpll_params->sd << PLL_SD_SHIFT;
    139 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val);
    140 
    141 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO);
    142 
    143 	return omap_pipe3_wait_lock(phy);
    144 }
    145 
    146 static void omap_control_phy_power(struct omap_pipe3 *phy, int on)
    147 {
    148 	u32 val, rate;
    149 
    150 	val = readl(phy->power_reg);
    151 
    152 	rate = get_sys_clk_freq();
    153 	rate = rate/1000000;
    154 
    155 	if (on) {
    156 		val &= ~(OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK |
    157 				OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK);
    158 		val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWERON <<
    159 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
    160 		val |= rate <<
    161 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT;
    162 	} else {
    163 		val &= ~OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK;
    164 		val |= OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF <<
    165 			OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT;
    166 	}
    167 
    168 	writel(val, phy->power_reg);
    169 }
    170 
    171 int phy_pipe3_power_on(struct omap_pipe3 *phy)
    172 {
    173 	int ret;
    174 	u32 val;
    175 
    176 	/* Program the DPLL only if not locked */
    177 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
    178 	if (!(val & PLL_LOCK)) {
    179 		ret = omap_pipe3_dpll_program(phy);
    180 		if (ret)
    181 			return ret;
    182 	} else {
    183 		/* else just bring it out of IDLE mode */
    184 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
    185 		if (val & PLL_IDLE) {
    186 			val &= ~PLL_IDLE;
    187 			omap_pipe3_writel(phy->pll_ctrl_base,
    188 					  PLL_CONFIGURATION2, val);
    189 			ret = omap_pipe3_wait_lock(phy);
    190 			if (ret)
    191 				return ret;
    192 		}
    193 	}
    194 
    195 	/* Power up the PHY */
    196 	omap_control_phy_power(phy, 1);
    197 
    198 	return 0;
    199 }
    200 
    201 int phy_pipe3_power_off(struct omap_pipe3 *phy)
    202 {
    203 	u32 val;
    204 	int timeout = PLL_IDLE_TIME;
    205 
    206 	/* Power down the PHY */
    207 	omap_control_phy_power(phy, 0);
    208 
    209 	/* Put DPLL in IDLE mode */
    210 	val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2);
    211 	val |= PLL_IDLE;
    212 	omap_pipe3_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val);
    213 
    214 	/* wait for LDO and Oscillator to power down */
    215 	do {
    216 		mdelay(1);
    217 		val = omap_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS);
    218 		if ((val & PLL_TICOPWDN) && (val & PLL_LDOPWDN))
    219 			break;
    220 	} while (--timeout);
    221 
    222 	if (!(val & PLL_TICOPWDN) || !(val & PLL_LDOPWDN)) {
    223 		printf("%s: Failed to power down DPLL: PLL_STATUS 0x%x\n",
    224 		       __func__, val);
    225 		return -EBUSY;
    226 	}
    227 
    228 	return 0;
    229 }
    230 
    231