cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy-exynos4210-usb2.c (7036B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Samsung SoC USB 1.1/2.0 PHY driver - Exynos 4210 support
      4 *
      5 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
      6 * Author: Kamil Debski <k.debski@samsung.com>
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/io.h>
     11#include <linux/phy/phy.h>
     12#include <linux/regmap.h>
     13#include "phy-samsung-usb2.h"
     14
     15/* Exynos USB PHY registers */
     16
     17/* PHY power control */
     18#define EXYNOS_4210_UPHYPWR			0x0
     19
     20#define EXYNOS_4210_UPHYPWR_PHY0_SUSPEND	BIT(0)
     21#define EXYNOS_4210_UPHYPWR_PHY0_PWR		BIT(3)
     22#define EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR	BIT(4)
     23#define EXYNOS_4210_UPHYPWR_PHY0_SLEEP		BIT(5)
     24#define EXYNOS_4210_UPHYPWR_PHY0	( \
     25	EXYNOS_4210_UPHYPWR_PHY0_SUSPEND | \
     26	EXYNOS_4210_UPHYPWR_PHY0_PWR | \
     27	EXYNOS_4210_UPHYPWR_PHY0_OTG_PWR | \
     28	EXYNOS_4210_UPHYPWR_PHY0_SLEEP)
     29
     30#define EXYNOS_4210_UPHYPWR_PHY1_SUSPEND	BIT(6)
     31#define EXYNOS_4210_UPHYPWR_PHY1_PWR		BIT(7)
     32#define EXYNOS_4210_UPHYPWR_PHY1_SLEEP		BIT(8)
     33#define EXYNOS_4210_UPHYPWR_PHY1 ( \
     34	EXYNOS_4210_UPHYPWR_PHY1_SUSPEND | \
     35	EXYNOS_4210_UPHYPWR_PHY1_PWR | \
     36	EXYNOS_4210_UPHYPWR_PHY1_SLEEP)
     37
     38#define EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND	BIT(9)
     39#define EXYNOS_4210_UPHYPWR_HSIC0_SLEEP		BIT(10)
     40#define EXYNOS_4210_UPHYPWR_HSIC0 ( \
     41	EXYNOS_4210_UPHYPWR_HSIC0_SUSPEND | \
     42	EXYNOS_4210_UPHYPWR_HSIC0_SLEEP)
     43
     44#define EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND	BIT(11)
     45#define EXYNOS_4210_UPHYPWR_HSIC1_SLEEP		BIT(12)
     46#define EXYNOS_4210_UPHYPWR_HSIC1 ( \
     47	EXYNOS_4210_UPHYPWR_HSIC1_SUSPEND | \
     48	EXYNOS_4210_UPHYPWR_HSIC1_SLEEP)
     49
     50/* PHY clock control */
     51#define EXYNOS_4210_UPHYCLK			0x4
     52
     53#define EXYNOS_4210_UPHYCLK_PHYFSEL_MASK	(0x3 << 0)
     54#define EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET	0
     55#define EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ	(0x0 << 0)
     56#define EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ	(0x3 << 0)
     57#define EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ	(0x2 << 0)
     58
     59#define EXYNOS_4210_UPHYCLK_PHY0_ID_PULLUP	BIT(2)
     60#define EXYNOS_4210_UPHYCLK_PHY0_COMMON_ON	BIT(4)
     61#define EXYNOS_4210_UPHYCLK_PHY1_COMMON_ON	BIT(7)
     62
     63/* PHY reset control */
     64#define EXYNOS_4210_UPHYRST			0x8
     65
     66#define EXYNOS_4210_URSTCON_PHY0		BIT(0)
     67#define EXYNOS_4210_URSTCON_OTG_HLINK		BIT(1)
     68#define EXYNOS_4210_URSTCON_OTG_PHYLINK		BIT(2)
     69#define EXYNOS_4210_URSTCON_PHY1_ALL		BIT(3)
     70#define EXYNOS_4210_URSTCON_PHY1_P0		BIT(4)
     71#define EXYNOS_4210_URSTCON_PHY1_P1P2		BIT(5)
     72#define EXYNOS_4210_URSTCON_HOST_LINK_ALL	BIT(6)
     73#define EXYNOS_4210_URSTCON_HOST_LINK_P0	BIT(7)
     74#define EXYNOS_4210_URSTCON_HOST_LINK_P1	BIT(8)
     75#define EXYNOS_4210_URSTCON_HOST_LINK_P2	BIT(9)
     76
     77/* Isolation, configured in the power management unit */
     78#define EXYNOS_4210_USB_ISOL_DEVICE_OFFSET	0x704
     79#define EXYNOS_4210_USB_ISOL_DEVICE		BIT(0)
     80#define EXYNOS_4210_USB_ISOL_HOST_OFFSET	0x708
     81#define EXYNOS_4210_USB_ISOL_HOST		BIT(0)
     82
     83/* USBYPHY1 Floating prevention */
     84#define EXYNOS_4210_UPHY1CON			0x34
     85#define EXYNOS_4210_UPHY1CON_FLOAT_PREVENTION	0x1
     86
     87/* Mode switching SUB Device <-> Host */
     88#define EXYNOS_4210_MODE_SWITCH_OFFSET		0x21c
     89#define EXYNOS_4210_MODE_SWITCH_MASK		1
     90#define EXYNOS_4210_MODE_SWITCH_DEVICE		0
     91#define EXYNOS_4210_MODE_SWITCH_HOST		1
     92
     93enum exynos4210_phy_id {
     94	EXYNOS4210_DEVICE,
     95	EXYNOS4210_HOST,
     96	EXYNOS4210_HSIC0,
     97	EXYNOS4210_HSIC1,
     98	EXYNOS4210_NUM_PHYS,
     99};
    100
    101/*
    102 * exynos4210_rate_to_clk() converts the supplied clock rate to the value that
    103 * can be written to the phy register.
    104 */
    105static int exynos4210_rate_to_clk(unsigned long rate, u32 *reg)
    106{
    107	switch (rate) {
    108	case 12 * MHZ:
    109		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_12MHZ;
    110		break;
    111	case 24 * MHZ:
    112		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_24MHZ;
    113		break;
    114	case 48 * MHZ:
    115		*reg = EXYNOS_4210_UPHYCLK_PHYFSEL_48MHZ;
    116		break;
    117	default:
    118		return -EINVAL;
    119	}
    120
    121	return 0;
    122}
    123
    124static void exynos4210_isol(struct samsung_usb2_phy_instance *inst, bool on)
    125{
    126	struct samsung_usb2_phy_driver *drv = inst->drv;
    127	u32 offset;
    128	u32 mask;
    129
    130	switch (inst->cfg->id) {
    131	case EXYNOS4210_DEVICE:
    132		offset = EXYNOS_4210_USB_ISOL_DEVICE_OFFSET;
    133		mask = EXYNOS_4210_USB_ISOL_DEVICE;
    134		break;
    135	case EXYNOS4210_HOST:
    136		offset = EXYNOS_4210_USB_ISOL_HOST_OFFSET;
    137		mask = EXYNOS_4210_USB_ISOL_HOST;
    138		break;
    139	default:
    140		return;
    141	}
    142
    143	regmap_update_bits(drv->reg_pmu, offset, mask, on ? 0 : mask);
    144}
    145
    146static void exynos4210_phy_pwr(struct samsung_usb2_phy_instance *inst, bool on)
    147{
    148	struct samsung_usb2_phy_driver *drv = inst->drv;
    149	u32 rstbits = 0;
    150	u32 phypwr = 0;
    151	u32 rst;
    152	u32 pwr;
    153	u32 clk;
    154
    155	switch (inst->cfg->id) {
    156	case EXYNOS4210_DEVICE:
    157		phypwr =	EXYNOS_4210_UPHYPWR_PHY0;
    158		rstbits =	EXYNOS_4210_URSTCON_PHY0;
    159		break;
    160	case EXYNOS4210_HOST:
    161		phypwr =	EXYNOS_4210_UPHYPWR_PHY1;
    162		rstbits =	EXYNOS_4210_URSTCON_PHY1_ALL |
    163				EXYNOS_4210_URSTCON_PHY1_P0 |
    164				EXYNOS_4210_URSTCON_PHY1_P1P2 |
    165				EXYNOS_4210_URSTCON_HOST_LINK_ALL |
    166				EXYNOS_4210_URSTCON_HOST_LINK_P0;
    167		writel(on, drv->reg_phy + EXYNOS_4210_UPHY1CON);
    168		break;
    169	case EXYNOS4210_HSIC0:
    170		phypwr =	EXYNOS_4210_UPHYPWR_HSIC0;
    171		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
    172				EXYNOS_4210_URSTCON_HOST_LINK_P1;
    173		break;
    174	case EXYNOS4210_HSIC1:
    175		phypwr =	EXYNOS_4210_UPHYPWR_HSIC1;
    176		rstbits =	EXYNOS_4210_URSTCON_PHY1_P1P2 |
    177				EXYNOS_4210_URSTCON_HOST_LINK_P2;
    178		break;
    179	}
    180
    181	if (on) {
    182		clk = readl(drv->reg_phy + EXYNOS_4210_UPHYCLK);
    183		clk &= ~EXYNOS_4210_UPHYCLK_PHYFSEL_MASK;
    184		clk |= drv->ref_reg_val << EXYNOS_4210_UPHYCLK_PHYFSEL_OFFSET;
    185		writel(clk, drv->reg_phy + EXYNOS_4210_UPHYCLK);
    186
    187		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
    188		pwr &= ~phypwr;
    189		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
    190
    191		rst = readl(drv->reg_phy + EXYNOS_4210_UPHYRST);
    192		rst |= rstbits;
    193		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
    194		udelay(10);
    195		rst &= ~rstbits;
    196		writel(rst, drv->reg_phy + EXYNOS_4210_UPHYRST);
    197		/* The following delay is necessary for the reset sequence to be
    198		 * completed */
    199		udelay(80);
    200	} else {
    201		pwr = readl(drv->reg_phy + EXYNOS_4210_UPHYPWR);
    202		pwr |= phypwr;
    203		writel(pwr, drv->reg_phy + EXYNOS_4210_UPHYPWR);
    204	}
    205}
    206
    207static int exynos4210_power_on(struct samsung_usb2_phy_instance *inst)
    208{
    209	/* Order of initialisation is important - first power then isolation */
    210	exynos4210_phy_pwr(inst, 1);
    211	exynos4210_isol(inst, 0);
    212
    213	return 0;
    214}
    215
    216static int exynos4210_power_off(struct samsung_usb2_phy_instance *inst)
    217{
    218	exynos4210_isol(inst, 1);
    219	exynos4210_phy_pwr(inst, 0);
    220
    221	return 0;
    222}
    223
    224
    225static const struct samsung_usb2_common_phy exynos4210_phys[] = {
    226	{
    227		.label		= "device",
    228		.id		= EXYNOS4210_DEVICE,
    229		.power_on	= exynos4210_power_on,
    230		.power_off	= exynos4210_power_off,
    231	},
    232	{
    233		.label		= "host",
    234		.id		= EXYNOS4210_HOST,
    235		.power_on	= exynos4210_power_on,
    236		.power_off	= exynos4210_power_off,
    237	},
    238	{
    239		.label		= "hsic0",
    240		.id		= EXYNOS4210_HSIC0,
    241		.power_on	= exynos4210_power_on,
    242		.power_off	= exynos4210_power_off,
    243	},
    244	{
    245		.label		= "hsic1",
    246		.id		= EXYNOS4210_HSIC1,
    247		.power_on	= exynos4210_power_on,
    248		.power_off	= exynos4210_power_off,
    249	},
    250};
    251
    252const struct samsung_usb2_phy_config exynos4210_usb2_phy_config = {
    253	.has_mode_switch	= 0,
    254	.num_phys		= EXYNOS4210_NUM_PHYS,
    255	.phys			= exynos4210_phys,
    256	.rate_to_clk		= exynos4210_rate_to_clk,
    257};