Lines Matching +full:control +full:- +full:parent
1 // SPDX-License-Identifier: GPL-2.0+
10 * Provides a simple driver to control the ASPEED P2A interface which allows
28 #include <linux/aspeed-p2a-ctrl.h>
30 #define DEVICE_NAME "aspeed-p2a-ctrl"
32 /* SCU2C is a Misc. Control Register. */
34 /* SCU180 is the PCIe Configuration Setting Control Register. */
74 struct aspeed_p2a_ctrl *parent; member
91 regmap_update_bits(p2a_ctrl->regmap, in aspeed_p2a_enable_bridge()
97 regmap_update_bits(p2a_ctrl->regmap, SCU180, SCU180_ENP2A, 0); in aspeed_p2a_disable_bridge()
104 struct aspeed_p2a_user *priv = file->private_data; in aspeed_p2a_mmap()
105 struct aspeed_p2a_ctrl *ctrl = priv->parent; in aspeed_p2a_mmap()
107 if (ctrl->mem_base == 0 && ctrl->mem_size == 0) in aspeed_p2a_mmap()
108 return -EINVAL; in aspeed_p2a_mmap()
110 vsize = vma->vm_end - vma->vm_start; in aspeed_p2a_mmap()
111 prot = vma->vm_page_prot; in aspeed_p2a_mmap()
113 if (vma->vm_pgoff + vsize > ctrl->mem_base + ctrl->mem_size) in aspeed_p2a_mmap()
114 return -EINVAL; in aspeed_p2a_mmap()
119 if (remap_pfn_range(vma, vma->vm_start, in aspeed_p2a_mmap()
120 (ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff, in aspeed_p2a_mmap()
122 return -EAGAIN; in aspeed_p2a_mmap()
135 base = map->addr; in aspeed_p2a_region_acquire()
136 end = map->addr + (map->length - 1); in aspeed_p2a_region_acquire()
140 const struct region *curr = &ctrl->config->regions[i]; in aspeed_p2a_region_acquire()
144 if (curr->max < base) in aspeed_p2a_region_acquire()
149 if (curr->min > end) in aspeed_p2a_region_acquire()
155 mutex_lock(&ctrl->tracking); in aspeed_p2a_region_acquire()
156 ctrl->readerwriters[i] += 1; in aspeed_p2a_region_acquire()
157 mutex_unlock(&ctrl->tracking); in aspeed_p2a_region_acquire()
162 priv->readwrite[i] += 1; in aspeed_p2a_region_acquire()
164 /* Enable the region as read-write. */ in aspeed_p2a_region_acquire()
165 regmap_update_bits(ctrl->regmap, SCU2C, curr->bit, 0); in aspeed_p2a_region_acquire()
175 struct aspeed_p2a_user *priv = file->private_data; in aspeed_p2a_ioctl()
176 struct aspeed_p2a_ctrl *ctrl = priv->parent; in aspeed_p2a_ioctl()
181 return -EFAULT; in aspeed_p2a_ioctl()
185 /* If they want a region to be read-only, since the entire in aspeed_p2a_ioctl()
186 * region is read-only once enabled, we just need to track this in aspeed_p2a_ioctl()
191 mutex_lock(&ctrl->tracking); in aspeed_p2a_ioctl()
192 ctrl->readers += 1; in aspeed_p2a_ioctl()
193 mutex_unlock(&ctrl->tracking); in aspeed_p2a_ioctl()
198 priv->read += 1; in aspeed_p2a_ioctl()
202 return -EINVAL; in aspeed_p2a_ioctl()
206 return -EINVAL; in aspeed_p2a_ioctl()
212 /* This is a request for the memory-region and corresponding in aspeed_p2a_ioctl()
217 map.addr = ctrl->mem_base; in aspeed_p2a_ioctl()
218 map.length = ctrl->mem_size; in aspeed_p2a_ioctl()
220 return copy_to_user(arg, &map, sizeof(map)) ? -EFAULT : 0; in aspeed_p2a_ioctl()
223 return -EINVAL; in aspeed_p2a_ioctl()
230 * A user can map a region as read-only (bridge enabled), or read-write (bit
243 return -ENOMEM; in aspeed_p2a_open()
245 priv->file = file; in aspeed_p2a_open()
246 priv->read = 0; in aspeed_p2a_open()
247 memset(priv->readwrite, 0, sizeof(priv->readwrite)); in aspeed_p2a_open()
250 priv->parent = file->private_data; in aspeed_p2a_open()
253 file->private_data = priv; in aspeed_p2a_open()
268 struct aspeed_p2a_user *priv = file->private_data; in aspeed_p2a_release()
273 mutex_lock(&priv->parent->tracking); in aspeed_p2a_release()
275 priv->parent->readers -= priv->read; in aspeed_p2a_release()
278 priv->parent->readerwriters[i] -= priv->readwrite[i]; in aspeed_p2a_release()
280 if (priv->parent->readerwriters[i] > 0) in aspeed_p2a_release()
283 bits |= priv->parent->config->regions[i].bit; in aspeed_p2a_release()
294 regmap_update_bits(priv->parent->regmap, SCU2C, bits, bits); in aspeed_p2a_release()
296 /* If parent->readers is zero and open windows is 0, disable the in aspeed_p2a_release()
299 if (!open_regions && priv->parent->readers == 0) in aspeed_p2a_release()
300 aspeed_p2a_disable_bridge(priv->parent); in aspeed_p2a_release()
302 mutex_unlock(&priv->parent->tracking); in aspeed_p2a_release()
324 value |= p2a_ctrl->config->regions[i].bit; in aspeed_p2a_disable_all()
326 regmap_update_bits(p2a_ctrl->regmap, SCU2C, value, value); in aspeed_p2a_disable_all()
340 dev = &pdev->dev; in aspeed_p2a_ctrl_probe()
344 return -ENOMEM; in aspeed_p2a_ctrl_probe()
346 mutex_init(&misc_ctrl->tracking); in aspeed_p2a_ctrl_probe()
349 node = of_parse_phandle(dev->of_node, "memory-region", 0); in aspeed_p2a_ctrl_probe()
355 return -ENODEV; in aspeed_p2a_ctrl_probe()
358 misc_ctrl->mem_size = resource_size(&resm); in aspeed_p2a_ctrl_probe()
359 misc_ctrl->mem_base = resm.start; in aspeed_p2a_ctrl_probe()
362 misc_ctrl->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node); in aspeed_p2a_ctrl_probe()
363 if (IS_ERR(misc_ctrl->regmap)) { in aspeed_p2a_ctrl_probe()
365 return -ENODEV; in aspeed_p2a_ctrl_probe()
368 misc_ctrl->config = of_device_get_match_data(dev); in aspeed_p2a_ctrl_probe()
370 dev_set_drvdata(&pdev->dev, misc_ctrl); in aspeed_p2a_ctrl_probe()
374 misc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR; in aspeed_p2a_ctrl_probe()
375 misc_ctrl->miscdev.name = DEVICE_NAME; in aspeed_p2a_ctrl_probe()
376 misc_ctrl->miscdev.fops = &aspeed_p2a_ctrl_fops; in aspeed_p2a_ctrl_probe()
377 misc_ctrl->miscdev.parent = dev; in aspeed_p2a_ctrl_probe()
379 rc = misc_register(&misc_ctrl->miscdev); in aspeed_p2a_ctrl_probe()
388 struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev); in aspeed_p2a_ctrl_remove()
390 misc_deregister(&p2a_ctrl->miscdev); in aspeed_p2a_ctrl_remove()
423 { .compatible = "aspeed,ast2400-p2a-ctrl",
425 { .compatible = "aspeed,ast2500-p2a-ctrl",
444 MODULE_DESCRIPTION("Control for aspeed 2400/2500 P2A VGA HOST to BMC mappings");