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