xref: /linux/drivers/soc/aspeed/aspeed-lpc-ctrl.c (revision 58f6259b7a08f8d47d4629609703d358b042f0fd)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2017 IBM Corporation
4  */
5 
6 #include <linux/clk.h>
7 #include <linux/log2.h>
8 #include <linux/mfd/syscon.h>
9 #include <linux/miscdevice.h>
10 #include <linux/mm.h>
11 #include <linux/module.h>
12 #include <linux/of_address.h>
13 #include <linux/platform_device.h>
14 #include <linux/poll.h>
15 #include <linux/regmap.h>
16 
17 #include <linux/aspeed-lpc-ctrl.h>
18 
19 #define DEVICE_NAME	"aspeed-lpc-ctrl"
20 
21 #define HICR5 0x80
22 #define HICR5_ENL2H	BIT(8)
23 #define HICR5_ENFWH	BIT(10)
24 
25 #define HICR6 0x84
26 #define SW_FWH2AHB	BIT(17)
27 
28 #define HICR7 0x88
29 #define HICR8 0x8c
30 
31 struct aspeed_lpc_ctrl {
32 	struct miscdevice	miscdev;
33 	struct regmap		*regmap;
34 	struct clk		*clk;
35 	phys_addr_t		mem_base;
36 	resource_size_t		mem_size;
37 	u32			pnor_size;
38 	u32			pnor_base;
39 	bool			fwh2ahb;
40 	struct regmap		*scu;
41 };
42 
43 static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
44 {
45 	return container_of(file->private_data, struct aspeed_lpc_ctrl,
46 			miscdev);
47 }
48 
49 static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma)
50 {
51 	struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
52 	unsigned long vsize = vma->vm_end - vma->vm_start;
53 	pgprot_t prot = vma->vm_page_prot;
54 
55 	if (vma->vm_pgoff + vma_pages(vma) > lpc_ctrl->mem_size >> PAGE_SHIFT)
56 		return -EINVAL;
57 
58 	/* ast2400/2500 AHB accesses are not cache coherent */
59 	prot = pgprot_noncached(prot);
60 
61 	if (remap_pfn_range(vma, vma->vm_start,
62 		(lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
63 		vsize, prot))
64 		return -EAGAIN;
65 
66 	return 0;
67 }
68 
69 static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
70 		unsigned long param)
71 {
72 	struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
73 	struct device *dev = file->private_data;
74 	void __user *p = (void __user *)param;
75 	struct aspeed_lpc_ctrl_mapping map;
76 	u32 addr;
77 	u32 size;
78 	long rc;
79 
80 	if (copy_from_user(&map, p, sizeof(map)))
81 		return -EFAULT;
82 
83 	if (map.flags != 0)
84 		return -EINVAL;
85 
86 	switch (cmd) {
87 	case ASPEED_LPC_CTRL_IOCTL_GET_SIZE:
88 		/* The flash windows don't report their size */
89 		if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY)
90 			return -EINVAL;
91 
92 		/* Support more than one window id in the future */
93 		if (map.window_id != 0)
94 			return -EINVAL;
95 
96 		/* If memory-region is not described in device tree */
97 		if (!lpc_ctrl->mem_size) {
98 			dev_dbg(dev, "Didn't find reserved memory\n");
99 			return -ENXIO;
100 		}
101 
102 		map.size = lpc_ctrl->mem_size;
103 
104 		return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
105 	case ASPEED_LPC_CTRL_IOCTL_MAP:
106 
107 		/*
108 		 * The top half of HICR7 is the MSB of the BMC address of the
109 		 * mapping.
110 		 * The bottom half of HICR7 is the MSB of the HOST LPC
111 		 * firmware space address of the mapping.
112 		 *
113 		 * The 1 bits in the top of half of HICR8 represent the bits
114 		 * (in the requested address) that should be ignored and
115 		 * replaced with those from the top half of HICR7.
116 		 * The 1 bits in the bottom half of HICR8 represent the bits
117 		 * (in the requested address) that should be kept and pass
118 		 * into the BMC address space.
119 		 */
120 
121 		/*
122 		 * It doesn't make sense to talk about a size or offset with
123 		 * low 16 bits set. Both HICR7 and HICR8 talk about the top 16
124 		 * bits of addresses and sizes.
125 		 */
126 
127 		if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff))
128 			return -EINVAL;
129 
130 		/*
131 		 * Because of the way the masks work in HICR8 offset has to
132 		 * be a multiple of size.
133 		 */
134 		if (map.offset & (map.size - 1))
135 			return -EINVAL;
136 
137 		if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
138 			if (!lpc_ctrl->pnor_size) {
139 				dev_dbg(dev, "Didn't find host pnor flash\n");
140 				return -ENXIO;
141 			}
142 			addr = lpc_ctrl->pnor_base;
143 			size = lpc_ctrl->pnor_size;
144 		} else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
145 			/* If memory-region is not described in device tree */
146 			if (!lpc_ctrl->mem_size) {
147 				dev_dbg(dev, "Didn't find reserved memory\n");
148 				return -ENXIO;
149 			}
150 			addr = lpc_ctrl->mem_base;
151 			size = lpc_ctrl->mem_size;
152 		} else {
153 			return -EINVAL;
154 		}
155 
156 		/* Check overflow first! */
157 		if (map.offset + map.size < map.offset ||
158 			map.offset + map.size > size)
159 			return -EINVAL;
160 
161 		if (map.size == 0 || map.size > size)
162 			return -EINVAL;
163 
164 		addr += map.offset;
165 
166 		/*
167 		 * addr (host lpc address) is safe regardless of values. This
168 		 * simply changes the address the host has to request on its
169 		 * side of the LPC bus. This cannot impact the hosts own
170 		 * memory space by surprise as LPC specific accessors are
171 		 * required. The only strange thing that could be done is
172 		 * setting the lower 16 bits but the shift takes care of that.
173 		 */
174 
175 		rc = regmap_write(lpc_ctrl->regmap, HICR7,
176 				(addr | (map.addr >> 16)));
177 		if (rc)
178 			return rc;
179 
180 		rc = regmap_write(lpc_ctrl->regmap, HICR8,
181 				(~(map.size - 1)) | ((map.size >> 16) - 1));
182 		if (rc)
183 			return rc;
184 
185 		/*
186 		 * Switch to FWH2AHB mode, AST2600 only.
187 		 */
188 		if (lpc_ctrl->fwh2ahb) {
189 			/*
190 			 * Enable FWH2AHB in SCU debug control register 2. This
191 			 * does not turn it on, but makes it available for it
192 			 * to be configured in HICR6.
193 			 */
194 			regmap_update_bits(lpc_ctrl->scu, 0x0D8, BIT(2), 0);
195 
196 			/*
197 			 * The other bits in this register are interrupt status bits
198 			 * that are cleared by writing 1. As we don't want to clear
199 			 * them, set only the bit of interest.
200 			 */
201 			regmap_write(lpc_ctrl->regmap, HICR6, SW_FWH2AHB);
202 		}
203 
204 		/*
205 		 * Enable LPC FHW cycles. This is required for the host to
206 		 * access the regions specified.
207 		 */
208 		return regmap_update_bits(lpc_ctrl->regmap, HICR5,
209 				HICR5_ENFWH | HICR5_ENL2H,
210 				HICR5_ENFWH | HICR5_ENL2H);
211 	}
212 
213 	return -EINVAL;
214 }
215 
216 static const struct file_operations aspeed_lpc_ctrl_fops = {
217 	.owner		= THIS_MODULE,
218 	.mmap		= aspeed_lpc_ctrl_mmap,
219 	.unlocked_ioctl	= aspeed_lpc_ctrl_ioctl,
220 };
221 
222 static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
223 {
224 	struct aspeed_lpc_ctrl *lpc_ctrl;
225 	struct device_node *node;
226 	struct resource resm;
227 	struct device *dev;
228 	struct device_node *np;
229 	int rc;
230 
231 	dev = &pdev->dev;
232 
233 	lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL);
234 	if (!lpc_ctrl)
235 		return -ENOMEM;
236 
237 	/* If flash is described in device tree then store */
238 	node = of_parse_phandle(dev->of_node, "flash", 0);
239 	if (!node) {
240 		dev_dbg(dev, "Didn't find host pnor flash node\n");
241 	} else {
242 		rc = of_address_to_resource(node, 1, &resm);
243 		of_node_put(node);
244 		if (rc) {
245 			dev_err(dev, "Couldn't address to resource for flash\n");
246 			return rc;
247 		}
248 
249 		lpc_ctrl->pnor_size = resource_size(&resm);
250 		lpc_ctrl->pnor_base = resm.start;
251 	}
252 
253 
254 	dev_set_drvdata(&pdev->dev, lpc_ctrl);
255 
256 	/* If memory-region is described in device tree then store */
257 	node = of_parse_phandle(dev->of_node, "memory-region", 0);
258 	if (!node) {
259 		dev_dbg(dev, "Didn't find reserved memory\n");
260 	} else {
261 		rc = of_address_to_resource(node, 0, &resm);
262 		of_node_put(node);
263 		if (rc) {
264 			dev_err(dev, "Couldn't address to resource for reserved memory\n");
265 			return -ENXIO;
266 		}
267 
268 		lpc_ctrl->mem_size = resource_size(&resm);
269 		lpc_ctrl->mem_base = resm.start;
270 
271 		if (!is_power_of_2(lpc_ctrl->mem_size)) {
272 			dev_err(dev, "Reserved memory size must be a power of 2, got %u\n",
273 			       (unsigned int)lpc_ctrl->mem_size);
274 			return -EINVAL;
275 		}
276 
277 		if (!IS_ALIGNED(lpc_ctrl->mem_base, lpc_ctrl->mem_size)) {
278 			dev_err(dev, "Reserved memory must be naturally aligned for size %u\n",
279 			       (unsigned int)lpc_ctrl->mem_size);
280 			return -EINVAL;
281 		}
282 	}
283 
284 	np = pdev->dev.parent->of_node;
285 	if (!of_device_is_compatible(np, "aspeed,ast2400-lpc-v2") &&
286 	    !of_device_is_compatible(np, "aspeed,ast2500-lpc-v2") &&
287 	    !of_device_is_compatible(np, "aspeed,ast2600-lpc-v2")) {
288 		dev_err(dev, "unsupported LPC device binding\n");
289 		return -ENODEV;
290 	}
291 
292 	lpc_ctrl->regmap = syscon_node_to_regmap(np);
293 	if (IS_ERR(lpc_ctrl->regmap)) {
294 		dev_err(dev, "Couldn't get regmap\n");
295 		return -ENODEV;
296 	}
297 
298 	if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-lpc-ctrl")) {
299 		lpc_ctrl->fwh2ahb = true;
300 
301 		lpc_ctrl->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2600-scu");
302 		if (IS_ERR(lpc_ctrl->scu)) {
303 			dev_err(dev, "couldn't find scu\n");
304 			return PTR_ERR(lpc_ctrl->scu);
305 		}
306 	}
307 
308 	lpc_ctrl->clk = devm_clk_get(dev, NULL);
309 	if (IS_ERR(lpc_ctrl->clk))
310 		return dev_err_probe(dev, PTR_ERR(lpc_ctrl->clk),
311 				     "couldn't get clock\n");
312 	rc = clk_prepare_enable(lpc_ctrl->clk);
313 	if (rc) {
314 		dev_err(dev, "couldn't enable clock\n");
315 		return rc;
316 	}
317 
318 	lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
319 	lpc_ctrl->miscdev.name = DEVICE_NAME;
320 	lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
321 	lpc_ctrl->miscdev.parent = dev;
322 	rc = misc_register(&lpc_ctrl->miscdev);
323 	if (rc) {
324 		dev_err(dev, "Unable to register device\n");
325 		goto err;
326 	}
327 
328 	return 0;
329 
330 err:
331 	clk_disable_unprepare(lpc_ctrl->clk);
332 	return rc;
333 }
334 
335 static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
336 {
337 	struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
338 
339 	misc_deregister(&lpc_ctrl->miscdev);
340 	clk_disable_unprepare(lpc_ctrl->clk);
341 
342 	return 0;
343 }
344 
345 static const struct of_device_id aspeed_lpc_ctrl_match[] = {
346 	{ .compatible = "aspeed,ast2400-lpc-ctrl" },
347 	{ .compatible = "aspeed,ast2500-lpc-ctrl" },
348 	{ .compatible = "aspeed,ast2600-lpc-ctrl" },
349 	{ },
350 };
351 
352 static struct platform_driver aspeed_lpc_ctrl_driver = {
353 	.driver = {
354 		.name		= DEVICE_NAME,
355 		.of_match_table = aspeed_lpc_ctrl_match,
356 	},
357 	.probe = aspeed_lpc_ctrl_probe,
358 	.remove = aspeed_lpc_ctrl_remove,
359 };
360 
361 module_platform_driver(aspeed_lpc_ctrl_driver);
362 
363 MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
364 MODULE_LICENSE("GPL");
365 MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>");
366 MODULE_DESCRIPTION("Control for ASPEED LPC HOST to BMC mappings");
367