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 void 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 343 static const struct of_device_id aspeed_lpc_ctrl_match[] = { 344 { .compatible = "aspeed,ast2400-lpc-ctrl" }, 345 { .compatible = "aspeed,ast2500-lpc-ctrl" }, 346 { .compatible = "aspeed,ast2600-lpc-ctrl" }, 347 { }, 348 }; 349 350 static struct platform_driver aspeed_lpc_ctrl_driver = { 351 .driver = { 352 .name = DEVICE_NAME, 353 .of_match_table = aspeed_lpc_ctrl_match, 354 }, 355 .probe = aspeed_lpc_ctrl_probe, 356 .remove_new = aspeed_lpc_ctrl_remove, 357 }; 358 359 module_platform_driver(aspeed_lpc_ctrl_driver); 360 361 MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match); 362 MODULE_LICENSE("GPL"); 363 MODULE_AUTHOR("Cyril Bur <cyrilbur@gmail.com>"); 364 MODULE_DESCRIPTION("Control for ASPEED LPC HOST to BMC mappings"); 365