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
18 struct mt7620_sysc_priv {
19 void __iomem *base;
20 };
21
mt7620_sysc_read(struct udevice * dev,int offset,void * buf,int size)22 static 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
mt7620_sysc_write(struct udevice * dev,int offset,const void * buf,int size)40 static 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
mt7620_sysc_ioctl(struct udevice * dev,unsigned long request,void * buf)56 static 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
mt7620_sysc_probe(struct udevice * dev)140 static 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
153 static struct misc_ops mt7620_sysc_ops = {
154 .read = mt7620_sysc_read,
155 .write = mt7620_sysc_write,
156 .ioctl = mt7620_sysc_ioctl,
157 };
158
159 static const struct udevice_id mt7620_sysc_ids[] = {
160 { .compatible = "mediatek,mt7620-sysc" },
161 { }
162 };
163
164 U_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