1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2020 MediaTek Inc. All Rights Reserved. 4 * 5 * Author: Weijie Gao <weijie.gao@mediatek.com> 6 * 7 * Misc driver for manipulating System control registers 8 */ 9 10#include <dm.h> 11#include <misc.h> 12#include <asm/io.h> 13#include <asm/addrspace.h> 14#include <dm/device_compat.h> 15#include <mach/mt7620-sysc.h> 16#include "mt7620.h" 17 18struct mt7620_sysc_priv { 19 void __iomem *base; 20}; 21 22static int mt7620_sysc_read(struct udevice *dev, int offset, void *buf, 23 int size) 24{ 25 struct mt7620_sysc_priv *priv = dev_get_priv(dev); 26 u32 val; 27 28 if (offset % sizeof(u32) || size != sizeof(u32) || 29 offset >= SYSCTL_SIZE) 30 return -EINVAL; 31 32 val = readl(priv->base + offset); 33 34 if (buf) 35 *(u32 *)buf = val; 36 37 return 0; 38} 39 40static int mt7620_sysc_write(struct udevice *dev, int offset, const void *buf, 41 int size) 42{ 43 struct mt7620_sysc_priv *priv = dev_get_priv(dev); 44 u32 val; 45 46 if (offset % sizeof(u32) || size != sizeof(u32) || 47 offset >= SYSCTL_SIZE || !buf) 48 return -EINVAL; 49 50 val = *(u32 *)buf; 51 writel(val, priv->base + offset); 52 53 return 0; 54} 55 56static int mt7620_sysc_ioctl(struct udevice *dev, unsigned long request, 57 void *buf) 58{ 59 struct mt7620_sysc_priv *priv = dev_get_priv(dev); 60 struct mt7620_sysc_chip_rev *chip_rev; 61 struct mt7620_sysc_clks *clks; 62 u32 val, shift; 63 64 if (!buf) 65 return -EINVAL; 66 67 switch (request) { 68 case MT7620_SYSC_IOCTL_GET_CLK: 69 clks = buf; 70 mt7620_get_clks(&clks->cpu_clk, &clks->sys_clk, 71 &clks->xtal_clk); 72 73 val = readl(priv->base + SYSCTL_CLKCFG0_REG); 74 if (val & PERI_CLK_SEL) 75 clks->peri_clk = clks->xtal_clk; 76 else 77 clks->peri_clk = 40000000; 78 79 return 0; 80 81 case MT7620_SYSC_IOCTL_GET_CHIP_REV: 82 chip_rev = buf; 83 84 val = readl(priv->base + SYSCTL_CHIP_REV_ID_REG); 85 86 chip_rev->bga = !!(val & PKG_ID); 87 chip_rev->ver = (val & VER_M) >> VER_S; 88 chip_rev->eco = (val & ECO_M) >> ECO_S; 89 90 return 0; 91 92 case MT7620_SYSC_IOCTL_SET_GE1_MODE: 93 case MT7620_SYSC_IOCTL_SET_GE2_MODE: 94 val = *(u32 *)buf; 95 96 if (val > MT7620_SYSC_GE_ESW_PHY) 97 return -EINVAL; 98 99 if (request == MT7620_SYSC_IOCTL_SET_GE1_MODE) 100 shift = GE1_MODE_S; 101 else 102 shift = GE2_MODE_S; 103 104 clrsetbits_32(priv->base + SYSCTL_SYSCFG1_REG, 105 GE_MODE_M << shift, val << shift); 106 107 return 0; 108 109 case MT7620_SYSC_IOCTL_SET_USB_MODE: 110 val = *(u32 *)buf; 111 112 if (val == MT7620_SYSC_USB_DEVICE_MODE) 113 val = 0; 114 else if (val == MT7620_SYSC_USB_HOST_MODE) 115 val = USB0_HOST_MODE; 116 117 clrsetbits_32(priv->base + SYSCTL_SYSCFG1_REG, 118 USB0_HOST_MODE, val); 119 120 return 0; 121 122 case MT7620_SYSC_IOCTL_SET_PCIE_MODE: 123 val = *(u32 *)buf; 124 125 if (val == MT7620_SYSC_PCIE_EP_MODE) 126 val = 0; 127 else if (val == MT7620_SYSC_PCIE_RC_MODE) 128 val = PCIE_RC_MODE; 129 130 clrsetbits_32(priv->base + SYSCTL_SYSCFG1_REG, 131 PCIE_RC_MODE, val); 132 133 return 0; 134 135 default: 136 return -EINVAL; 137 } 138} 139 140static int mt7620_sysc_probe(struct udevice *dev) 141{ 142 struct mt7620_sysc_priv *priv = dev_get_priv(dev); 143 144 priv->base = dev_remap_addr_index(dev, 0); 145 if (!priv->base) { 146 dev_err(dev, "failed to map sysc registers\n"); 147 return -EINVAL; 148 } 149 150 return 0; 151} 152 153static struct misc_ops mt7620_sysc_ops = { 154 .read = mt7620_sysc_read, 155 .write = mt7620_sysc_write, 156 .ioctl = mt7620_sysc_ioctl, 157}; 158 159static const struct udevice_id mt7620_sysc_ids[] = { 160 { .compatible = "mediatek,mt7620-sysc" }, 161 { } 162}; 163 164U_BOOT_DRIVER(mt7620_sysc) = { 165 .name = "mt7620_sysc", 166 .id = UCLASS_MISC, 167 .of_match = mt7620_sysc_ids, 168 .probe = mt7620_sysc_probe, 169 .ops = &mt7620_sysc_ops, 170 .priv_auto = sizeof(struct mt7620_sysc_priv), 171 .flags = DM_FLAG_PRE_RELOC, 172}; 173