linux/drivers/soc/aspeed/aspeed-p2a-ctrl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2019 Google Inc
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version
   8 * 2 of the License, or (at your option) any later version.
   9 *
  10 * Provides a simple driver to control the ASPEED P2A interface which allows
  11 * the host to read and write to various regions of the BMC's memory.
  12 */
  13
  14#include <linux/fs.h>
  15#include <linux/io.h>
  16#include <linux/mfd/syscon.h>
  17#include <linux/miscdevice.h>
  18#include <linux/mm.h>
  19#include <linux/module.h>
  20#include <linux/mutex.h>
  21#include <linux/of_address.h>
  22#include <linux/of_device.h>
  23#include <linux/platform_device.h>
  24#include <linux/regmap.h>
  25#include <linux/slab.h>
  26#include <linux/uaccess.h>
  27
  28#include <linux/aspeed-p2a-ctrl.h>
  29
  30#define DEVICE_NAME     "aspeed-p2a-ctrl"
  31
  32/* SCU2C is a Misc. Control Register. */
  33#define SCU2C 0x2c
  34/* SCU180 is the PCIe Configuration Setting Control Register. */
  35#define SCU180 0x180
  36/* Bit 1 controls the P2A bridge, while bit 0 controls the entire VGA device
  37 * on the PCI bus.
  38 */
  39#define SCU180_ENP2A BIT(1)
  40
  41/* The ast2400/2500 both have six ranges. */
  42#define P2A_REGION_COUNT 6
  43
  44struct region {
  45        u64 min;
  46        u64 max;
  47        u32 bit;
  48};
  49
  50struct aspeed_p2a_model_data {
  51        /* min, max, bit */
  52        struct region regions[P2A_REGION_COUNT];
  53};
  54
  55struct aspeed_p2a_ctrl {
  56        struct miscdevice miscdev;
  57        struct regmap *regmap;
  58
  59        const struct aspeed_p2a_model_data *config;
  60
  61        /* Access to these needs to be locked, held via probe, mapping ioctl,
  62         * and release, remove.
  63         */
  64        struct mutex tracking;
  65        u32 readers;
  66        u32 readerwriters[P2A_REGION_COUNT];
  67
  68        phys_addr_t mem_base;
  69        resource_size_t mem_size;
  70};
  71
  72struct aspeed_p2a_user {
  73        struct file *file;
  74        struct aspeed_p2a_ctrl *parent;
  75
  76        /* The entire memory space is opened for reading once the bridge is
  77         * enabled, therefore this needs only to be tracked once per user.
  78         * If any user has it open for read, the bridge must stay enabled.
  79         */
  80        u32 read;
  81
  82        /* Each entry of the array corresponds to a P2A Region.  If the user
  83         * opens for read or readwrite, the reference goes up here.  On
  84         * release, this array is walked and references adjusted accordingly.
  85         */
  86        u32 readwrite[P2A_REGION_COUNT];
  87};
  88
  89static void aspeed_p2a_enable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
  90{
  91        regmap_update_bits(p2a_ctrl->regmap,
  92                SCU180, SCU180_ENP2A, SCU180_ENP2A);
  93}
  94
  95static void aspeed_p2a_disable_bridge(struct aspeed_p2a_ctrl *p2a_ctrl)
  96{
  97        regmap_update_bits(p2a_ctrl->regmap, SCU180, SCU180_ENP2A, 0);
  98}
  99
 100static int aspeed_p2a_mmap(struct file *file, struct vm_area_struct *vma)
 101{
 102        unsigned long vsize;
 103        pgprot_t prot;
 104        struct aspeed_p2a_user *priv = file->private_data;
 105        struct aspeed_p2a_ctrl *ctrl = priv->parent;
 106
 107        if (ctrl->mem_base == 0 && ctrl->mem_size == 0)
 108                return -EINVAL;
 109
 110        vsize = vma->vm_end - vma->vm_start;
 111        prot = vma->vm_page_prot;
 112
 113        if (vma->vm_pgoff + vsize > ctrl->mem_base + ctrl->mem_size)
 114                return -EINVAL;
 115
 116        /* ast2400/2500 AHB accesses are not cache coherent */
 117        prot = pgprot_noncached(prot);
 118
 119        if (remap_pfn_range(vma, vma->vm_start,
 120                (ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
 121                vsize, prot))
 122                return -EAGAIN;
 123
 124        return 0;
 125}
 126
 127static bool aspeed_p2a_region_acquire(struct aspeed_p2a_user *priv,
 128                struct aspeed_p2a_ctrl *ctrl,
 129                struct aspeed_p2a_ctrl_mapping *map)
 130{
 131        int i;
 132        u64 base, end;
 133        bool matched = false;
 134
 135        base = map->addr;
 136        end = map->addr + (map->length - 1);
 137
 138        /* If the value is a legal u32, it will find a match. */
 139        for (i = 0; i < P2A_REGION_COUNT; i++) {
 140                const struct region *curr = &ctrl->config->regions[i];
 141
 142                /* If the top of this region is lower than your base, skip it.
 143                 */
 144                if (curr->max < base)
 145                        continue;
 146
 147                /* If the bottom of this region is higher than your end, bail.
 148                 */
 149                if (curr->min > end)
 150                        break;
 151
 152                /* Lock this and update it, therefore it someone else is
 153                 * closing their file out, this'll preserve the increment.
 154                 */
 155                mutex_lock(&ctrl->tracking);
 156                ctrl->readerwriters[i] += 1;
 157                mutex_unlock(&ctrl->tracking);
 158
 159                /* Track with the user, so when they close their file, we can
 160                 * decrement properly.
 161                 */
 162                priv->readwrite[i] += 1;
 163
 164                /* Enable the region as read-write. */
 165                regmap_update_bits(ctrl->regmap, SCU2C, curr->bit, 0);
 166                matched = true;
 167        }
 168
 169        return matched;
 170}
 171
 172static long aspeed_p2a_ioctl(struct file *file, unsigned int cmd,
 173                unsigned long data)
 174{
 175        struct aspeed_p2a_user *priv = file->private_data;
 176        struct aspeed_p2a_ctrl *ctrl = priv->parent;
 177        void __user *arg = (void __user *)data;
 178        struct aspeed_p2a_ctrl_mapping map;
 179
 180        if (copy_from_user(&map, arg, sizeof(map)))
 181                return -EFAULT;
 182
 183        switch (cmd) {
 184        case ASPEED_P2A_CTRL_IOCTL_SET_WINDOW:
 185                /* If they want a region to be read-only, since the entire
 186                 * region is read-only once enabled, we just need to track this
 187                 * user wants to read from the bridge, and if it's not enabled.
 188                 * Enable it.
 189                 */
 190                if (map.flags == ASPEED_P2A_CTRL_READ_ONLY) {
 191                        mutex_lock(&ctrl->tracking);
 192                        ctrl->readers += 1;
 193                        mutex_unlock(&ctrl->tracking);
 194
 195                        /* Track with the user, so when they close their file,
 196                         * we can decrement properly.
 197                         */
 198                        priv->read += 1;
 199                } else if (map.flags == ASPEED_P2A_CTRL_READWRITE) {
 200                        /* If we don't acquire any region return error. */
 201                        if (!aspeed_p2a_region_acquire(priv, ctrl, &map)) {
 202                                return -EINVAL;
 203                        }
 204                } else {
 205                        /* Invalid map flags. */
 206                        return -EINVAL;
 207                }
 208
 209                aspeed_p2a_enable_bridge(ctrl);
 210                return 0;
 211        case ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG:
 212                /* This is a request for the memory-region and corresponding
 213                 * length that is used by the driver for mmap.
 214                 */
 215
 216                map.flags = 0;
 217                map.addr = ctrl->mem_base;
 218                map.length = ctrl->mem_size;
 219
 220                return copy_to_user(arg, &map, sizeof(map)) ? -EFAULT : 0;
 221        }
 222
 223        return -EINVAL;
 224}
 225
 226
 227/*
 228 * When a user opens this file, we create a structure to track their mappings.
 229 *
 230 * A user can map a region as read-only (bridge enabled), or read-write (bit
 231 * flipped, and bridge enabled).  Either way, this tracking is used, s.t. when
 232 * they release the device references are handled.
 233 *
 234 * The bridge is not enabled until a user calls an ioctl to map a region,
 235 * simply opening the device does not enable it.
 236 */
 237static int aspeed_p2a_open(struct inode *inode, struct file *file)
 238{
 239        struct aspeed_p2a_user *priv;
 240
 241        priv = kmalloc(sizeof(*priv), GFP_KERNEL);
 242        if (!priv)
 243                return -ENOMEM;
 244
 245        priv->file = file;
 246        priv->read = 0;
 247        memset(priv->readwrite, 0, sizeof(priv->readwrite));
 248
 249        /* The file's private_data is initialized to the p2a_ctrl. */
 250        priv->parent = file->private_data;
 251
 252        /* Set the file's private_data to the user's data. */
 253        file->private_data = priv;
 254
 255        return 0;
 256}
 257
 258/*
 259 * This will close the users mappings.  It will go through what they had opened
 260 * for readwrite, and decrement those counts.  If at the end, this is the last
 261 * user, it'll close the bridge.
 262 */
 263static int aspeed_p2a_release(struct inode *inode, struct file *file)
 264{
 265        int i;
 266        u32 bits = 0;
 267        bool open_regions = false;
 268        struct aspeed_p2a_user *priv = file->private_data;
 269
 270        /* Lock others from changing these values until everything is updated
 271         * in one pass.
 272         */
 273        mutex_lock(&priv->parent->tracking);
 274
 275        priv->parent->readers -= priv->read;
 276
 277        for (i = 0; i < P2A_REGION_COUNT; i++) {
 278                priv->parent->readerwriters[i] -= priv->readwrite[i];
 279
 280                if (priv->parent->readerwriters[i] > 0)
 281                        open_regions = true;
 282                else
 283                        bits |= priv->parent->config->regions[i].bit;
 284        }
 285
 286        /* Setting a bit to 1 disables the region, so let's just OR with the
 287         * above to disable any.
 288         */
 289
 290        /* Note, if another user is trying to ioctl, they can't grab tracking,
 291         * and therefore can't grab either register mutex.
 292         * If another user is trying to close, they can't grab tracking either.
 293         */
 294        regmap_update_bits(priv->parent->regmap, SCU2C, bits, bits);
 295
 296        /* If parent->readers is zero and open windows is 0, disable the
 297         * bridge.
 298         */
 299        if (!open_regions && priv->parent->readers == 0)
 300                aspeed_p2a_disable_bridge(priv->parent);
 301
 302        mutex_unlock(&priv->parent->tracking);
 303
 304        kfree(priv);
 305
 306        return 0;
 307}
 308
 309static const struct file_operations aspeed_p2a_ctrl_fops = {
 310        .owner = THIS_MODULE,
 311        .mmap = aspeed_p2a_mmap,
 312        .unlocked_ioctl = aspeed_p2a_ioctl,
 313        .open = aspeed_p2a_open,
 314        .release = aspeed_p2a_release,
 315};
 316
 317/* The regions are controlled by SCU2C */
 318static void aspeed_p2a_disable_all(struct aspeed_p2a_ctrl *p2a_ctrl)
 319{
 320        int i;
 321        u32 value = 0;
 322
 323        for (i = 0; i < P2A_REGION_COUNT; i++)
 324                value |= p2a_ctrl->config->regions[i].bit;
 325
 326        regmap_update_bits(p2a_ctrl->regmap, SCU2C, value, value);
 327
 328        /* Disable the bridge. */
 329        aspeed_p2a_disable_bridge(p2a_ctrl);
 330}
 331
 332static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
 333{
 334        struct aspeed_p2a_ctrl *misc_ctrl;
 335        struct device *dev;
 336        struct resource resm;
 337        struct device_node *node;
 338        int rc = 0;
 339
 340        dev = &pdev->dev;
 341
 342        misc_ctrl = devm_kzalloc(dev, sizeof(*misc_ctrl), GFP_KERNEL);
 343        if (!misc_ctrl)
 344                return -ENOMEM;
 345
 346        mutex_init(&misc_ctrl->tracking);
 347
 348        /* optional. */
 349        node = of_parse_phandle(dev->of_node, "memory-region", 0);
 350        if (node) {
 351                rc = of_address_to_resource(node, 0, &resm);
 352                of_node_put(node);
 353                if (rc) {
 354                        dev_err(dev, "Couldn't address to resource for reserved memory\n");
 355                        return -ENODEV;
 356                }
 357
 358                misc_ctrl->mem_size = resource_size(&resm);
 359                misc_ctrl->mem_base = resm.start;
 360        }
 361
 362        misc_ctrl->regmap = syscon_node_to_regmap(pdev->dev.parent->of_node);
 363        if (IS_ERR(misc_ctrl->regmap)) {
 364                dev_err(dev, "Couldn't get regmap\n");
 365                return -ENODEV;
 366        }
 367
 368        misc_ctrl->config = of_device_get_match_data(dev);
 369
 370        dev_set_drvdata(&pdev->dev, misc_ctrl);
 371
 372        aspeed_p2a_disable_all(misc_ctrl);
 373
 374        misc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
 375        misc_ctrl->miscdev.name = DEVICE_NAME;
 376        misc_ctrl->miscdev.fops = &aspeed_p2a_ctrl_fops;
 377        misc_ctrl->miscdev.parent = dev;
 378
 379        rc = misc_register(&misc_ctrl->miscdev);
 380        if (rc)
 381                dev_err(dev, "Unable to register device\n");
 382
 383        return rc;
 384}
 385
 386static int aspeed_p2a_ctrl_remove(struct platform_device *pdev)
 387{
 388        struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev);
 389
 390        misc_deregister(&p2a_ctrl->miscdev);
 391
 392        return 0;
 393}
 394
 395#define SCU2C_DRAM      BIT(25)
 396#define SCU2C_SPI       BIT(24)
 397#define SCU2C_SOC       BIT(23)
 398#define SCU2C_FLASH     BIT(22)
 399
 400static const struct aspeed_p2a_model_data ast2400_model_data = {
 401        .regions = {
 402                {0x00000000, 0x17FFFFFF, SCU2C_FLASH},
 403                {0x18000000, 0x1FFFFFFF, SCU2C_SOC},
 404                {0x20000000, 0x2FFFFFFF, SCU2C_FLASH},
 405                {0x30000000, 0x3FFFFFFF, SCU2C_SPI},
 406                {0x40000000, 0x5FFFFFFF, SCU2C_DRAM},
 407                {0x60000000, 0xFFFFFFFF, SCU2C_SOC},
 408        }
 409};
 410
 411static const struct aspeed_p2a_model_data ast2500_model_data = {
 412        .regions = {
 413                {0x00000000, 0x0FFFFFFF, SCU2C_FLASH},
 414                {0x10000000, 0x1FFFFFFF, SCU2C_SOC},
 415                {0x20000000, 0x3FFFFFFF, SCU2C_FLASH},
 416                {0x40000000, 0x5FFFFFFF, SCU2C_SOC},
 417                {0x60000000, 0x7FFFFFFF, SCU2C_SPI},
 418                {0x80000000, 0xFFFFFFFF, SCU2C_DRAM},
 419        }
 420};
 421
 422static const struct of_device_id aspeed_p2a_ctrl_match[] = {
 423        { .compatible = "aspeed,ast2400-p2a-ctrl",
 424          .data = &ast2400_model_data },
 425        { .compatible = "aspeed,ast2500-p2a-ctrl",
 426          .data = &ast2500_model_data },
 427        { },
 428};
 429
 430static struct platform_driver aspeed_p2a_ctrl_driver = {
 431        .driver = {
 432                .name           = DEVICE_NAME,
 433                .of_match_table = aspeed_p2a_ctrl_match,
 434        },
 435        .probe = aspeed_p2a_ctrl_probe,
 436        .remove = aspeed_p2a_ctrl_remove,
 437};
 438
 439module_platform_driver(aspeed_p2a_ctrl_driver);
 440
 441MODULE_DEVICE_TABLE(of, aspeed_p2a_ctrl_match);
 442MODULE_LICENSE("GPL");
 443MODULE_AUTHOR("Patrick Venture <venture@google.com>");
 444MODULE_DESCRIPTION("Control for aspeed 2400/2500 P2A VGA HOST to BMC mappings");
 445