291 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (C) 2011 Marvell International Ltd. All rights reserved.4 * Copyright (C) 2018,2019 Lubomir Rintel <lkundrak@v3.sk>5 */6 7#include <linux/delay.h>8#include <linux/io.h>9#include <linux/mod_devicetable.h>10#include <linux/module.h>11#include <linux/phy/phy.h>12#include <linux/platform_device.h>13#include <linux/soc/mmp/cputype.h>14 15#define USB2_PLL_REG0 0x416#define USB2_PLL_REG1 0x817#define USB2_TX_REG0 0x1018#define USB2_TX_REG1 0x1419#define USB2_TX_REG2 0x1820#define USB2_RX_REG0 0x2021#define USB2_RX_REG1 0x2422#define USB2_RX_REG2 0x2823#define USB2_ANA_REG0 0x3024#define USB2_ANA_REG1 0x3425#define USB2_ANA_REG2 0x3826#define USB2_DIG_REG0 0x3C27#define USB2_DIG_REG1 0x4028#define USB2_DIG_REG2 0x4429#define USB2_DIG_REG3 0x4830#define USB2_TEST_REG0 0x4C31#define USB2_TEST_REG1 0x5032#define USB2_TEST_REG2 0x5433#define USB2_CHARGER_REG0 0x5834#define USB2_OTG_REG0 0x5C35#define USB2_PHY_MON0 0x6036#define USB2_RESETVE_REG0 0x6437#define USB2_ICID_REG0 0x7838#define USB2_ICID_REG1 0x7C39 40/* USB2_PLL_REG0 */41 42/* This is for Ax stepping */43#define USB2_PLL_FBDIV_SHIFT_MMP3 044#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)45 46#define USB2_PLL_REFDIV_SHIFT_MMP3 847#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)48 49#define USB2_PLL_VDD12_SHIFT_MMP3 1250#define USB2_PLL_VDD18_SHIFT_MMP3 1451 52/* This is for B0 stepping */53#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 054#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 955#define USB2_PLL_VDD18_SHIFT_MMP3_B0 1456#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF57#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E0058 59#define USB2_PLL_CAL12_SHIFT_MMP3 060#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)61 62#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 263 64#define USB2_PLL_KVCO_SHIFT_MMP3 465#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)66 67#define USB2_PLL_ICP_SHIFT_MMP3 868#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)69 70#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 1271 72#define USB2_PLL_PU_PLL_SHIFT_MMP3 1373#define USB2_PLL_PU_PLL_MASK (0x1 << 13)74 75#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)76 77/* USB2_TX_REG0 */78#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 879#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)80 81#define USB2_TX_RCAL_START_SHIFT_MMP3 1382 83/* USB2_TX_REG1 */84#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 085#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)86 87#define USB2_TX_AMP_SHIFT_MMP3 488#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)89 90#define USB2_TX_VDD12_SHIFT_MMP3 891#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)92 93/* USB2_TX_REG2 */94#define USB2_TX_DRV_SLEWRATE_SHIFT 1095 96/* USB2_RX_REG0 */97#define USB2_RX_SQ_THRESH_SHIFT_MMP3 498#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)99 100#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10101#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)102 103/* USB2_ANA_REG1*/104#define USB2_ANA_PU_ANA_SHIFT_MMP3 14105 106/* USB2_OTG_REG0 */107#define USB2_OTG_PU_OTG_SHIFT_MMP3 3108 109struct mmp3_usb_phy {110 struct phy *phy;111 void __iomem *base;112};113 114static unsigned int u2o_get(void __iomem *base, unsigned int offset)115{116 return readl_relaxed(base + offset);117}118 119static void u2o_set(void __iomem *base, unsigned int offset,120 unsigned int value)121{122 u32 reg;123 124 reg = readl_relaxed(base + offset);125 reg |= value;126 writel_relaxed(reg, base + offset);127 readl_relaxed(base + offset);128}129 130static void u2o_clear(void __iomem *base, unsigned int offset,131 unsigned int value)132{133 u32 reg;134 135 reg = readl_relaxed(base + offset);136 reg &= ~value;137 writel_relaxed(reg, base + offset);138 readl_relaxed(base + offset);139}140 141static int mmp3_usb_phy_init(struct phy *phy)142{143 struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);144 void __iomem *base = mmp3_usb_phy->base;145 146 if (cpu_is_mmp3_a0()) {147 u2o_clear(base, USB2_PLL_REG0, (USB2_PLL_FBDIV_MASK_MMP3148 | USB2_PLL_REFDIV_MASK_MMP3));149 u2o_set(base, USB2_PLL_REG0,150 0xd << USB2_PLL_REFDIV_SHIFT_MMP3151 | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3);152 } else if (cpu_is_mmp3_b0()) {153 u2o_clear(base, USB2_PLL_REG0, USB2_PLL_REFDIV_MASK_MMP3_B0154 | USB2_PLL_FBDIV_MASK_MMP3_B0);155 u2o_set(base, USB2_PLL_REG0,156 0xd << USB2_PLL_REFDIV_SHIFT_MMP3_B0157 | 0xf0 << USB2_PLL_FBDIV_SHIFT_MMP3_B0);158 } else {159 dev_err(&phy->dev, "unsupported silicon revision\n");160 return -ENODEV;161 }162 163 u2o_clear(base, USB2_PLL_REG1, USB2_PLL_PU_PLL_MASK164 | USB2_PLL_ICP_MASK_MMP3165 | USB2_PLL_KVCO_MASK_MMP3166 | USB2_PLL_CALI12_MASK_MMP3);167 u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_PU_PLL_SHIFT_MMP3168 | 1 << USB2_PLL_LOCK_BYPASS_SHIFT_MMP3169 | 3 << USB2_PLL_ICP_SHIFT_MMP3170 | 3 << USB2_PLL_KVCO_SHIFT_MMP3171 | 3 << USB2_PLL_CAL12_SHIFT_MMP3);172 173 u2o_clear(base, USB2_TX_REG0, USB2_TX_IMPCAL_VTH_MASK_MMP3);174 u2o_set(base, USB2_TX_REG0, 2 << USB2_TX_IMPCAL_VTH_SHIFT_MMP3);175 176 u2o_clear(base, USB2_TX_REG1, USB2_TX_VDD12_MASK_MMP3177 | USB2_TX_AMP_MASK_MMP3178 | USB2_TX_CK60_PHSEL_MASK_MMP3);179 u2o_set(base, USB2_TX_REG1, 3 << USB2_TX_VDD12_SHIFT_MMP3180 | 4 << USB2_TX_AMP_SHIFT_MMP3181 | 4 << USB2_TX_CK60_PHSEL_SHIFT_MMP3);182 183 u2o_clear(base, USB2_TX_REG2, 3 << USB2_TX_DRV_SLEWRATE_SHIFT);184 u2o_set(base, USB2_TX_REG2, 2 << USB2_TX_DRV_SLEWRATE_SHIFT);185 186 u2o_clear(base, USB2_RX_REG0, USB2_RX_SQ_THRESH_MASK_MMP3);187 u2o_set(base, USB2_RX_REG0, 0xa << USB2_RX_SQ_THRESH_SHIFT_MMP3);188 189 u2o_set(base, USB2_ANA_REG1, 0x1 << USB2_ANA_PU_ANA_SHIFT_MMP3);190 191 u2o_set(base, USB2_OTG_REG0, 0x1 << USB2_OTG_PU_OTG_SHIFT_MMP3);192 193 return 0;194}195 196static int mmp3_usb_phy_calibrate(struct phy *phy)197{198 struct mmp3_usb_phy *mmp3_usb_phy = phy_get_drvdata(phy);199 void __iomem *base = mmp3_usb_phy->base;200 int loops;201 202 /*203 * PLL VCO and TX Impedance Calibration Timing:204 *205 * _____________________________________206 * PU __________|207 * _____________________________208 * VCOCAL START _________|209 * ___210 * REG_RCAL_START ________________| |________|_______211 * | 200us | 400us | 40| 400us | USB PHY READY212 */213 214 udelay(200);215 u2o_set(base, USB2_PLL_REG1, 1 << USB2_PLL_VCOCAL_START_SHIFT_MMP3);216 udelay(400);217 u2o_set(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);218 udelay(40);219 u2o_clear(base, USB2_TX_REG0, 1 << USB2_TX_RCAL_START_SHIFT_MMP3);220 udelay(400);221 222 loops = 0;223 while ((u2o_get(base, USB2_PLL_REG1) & USB2_PLL_READY_MASK_MMP3) == 0) {224 mdelay(1);225 loops++;226 if (loops > 100) {227 dev_err(&phy->dev, "PLL_READY not set after 100mS.\n");228 return -ETIMEDOUT;229 }230 }231 232 return 0;233}234 235static const struct phy_ops mmp3_usb_phy_ops = {236 .init = mmp3_usb_phy_init,237 .calibrate = mmp3_usb_phy_calibrate,238 .owner = THIS_MODULE,239};240 241static const struct of_device_id mmp3_usb_phy_of_match[] = {242 { .compatible = "marvell,mmp3-usb-phy", },243 { },244};245MODULE_DEVICE_TABLE(of, mmp3_usb_phy_of_match);246 247static int mmp3_usb_phy_probe(struct platform_device *pdev)248{249 struct device *dev = &pdev->dev;250 struct mmp3_usb_phy *mmp3_usb_phy;251 struct phy_provider *provider;252 253 mmp3_usb_phy = devm_kzalloc(dev, sizeof(*mmp3_usb_phy), GFP_KERNEL);254 if (!mmp3_usb_phy)255 return -ENOMEM;256 257 mmp3_usb_phy->base = devm_platform_ioremap_resource(pdev, 0);258 if (IS_ERR(mmp3_usb_phy->base)) {259 dev_err(dev, "failed to remap PHY regs\n");260 return PTR_ERR(mmp3_usb_phy->base);261 }262 263 mmp3_usb_phy->phy = devm_phy_create(dev, NULL, &mmp3_usb_phy_ops);264 if (IS_ERR(mmp3_usb_phy->phy)) {265 dev_err(dev, "failed to create PHY\n");266 return PTR_ERR(mmp3_usb_phy->phy);267 }268 269 phy_set_drvdata(mmp3_usb_phy->phy, mmp3_usb_phy);270 provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);271 if (IS_ERR(provider)) {272 dev_err(dev, "failed to register PHY provider\n");273 return PTR_ERR(provider);274 }275 276 return 0;277}278 279static struct platform_driver mmp3_usb_phy_driver = {280 .probe = mmp3_usb_phy_probe,281 .driver = {282 .name = "mmp3-usb-phy",283 .of_match_table = mmp3_usb_phy_of_match,284 },285};286module_platform_driver(mmp3_usb_phy_driver);287 288MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");289MODULE_DESCRIPTION("Marvell MMP3 USB PHY Driver");290MODULE_LICENSE("GPL v2");291