linux/drivers/mfd/vexpress-sysreg.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License version 2 as
   4 * published by the Free Software Foundation.
   5 *
   6 * This program is distributed in the hope that it will be useful,
   7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   9 * GNU General Public License for more details.
  10 *
  11 * Copyright (C) 2012 ARM Limited
  12 */
  13
  14#include <linux/err.h>
  15#include <linux/gpio.h>
  16#include <linux/io.h>
  17#include <linux/leds.h>
  18#include <linux/of_address.h>
  19#include <linux/platform_device.h>
  20#include <linux/regulator/driver.h>
  21#include <linux/slab.h>
  22#include <linux/stat.h>
  23#include <linux/timer.h>
  24#include <linux/vexpress.h>
  25
  26#define SYS_ID                  0x000
  27#define SYS_SW                  0x004
  28#define SYS_LED                 0x008
  29#define SYS_100HZ               0x024
  30#define SYS_FLAGS               0x030
  31#define SYS_FLAGSSET            0x030
  32#define SYS_FLAGSCLR            0x034
  33#define SYS_NVFLAGS             0x038
  34#define SYS_NVFLAGSSET          0x038
  35#define SYS_NVFLAGSCLR          0x03c
  36#define SYS_MCI                 0x048
  37#define SYS_FLASH               0x04c
  38#define SYS_CFGSW               0x058
  39#define SYS_24MHZ               0x05c
  40#define SYS_MISC                0x060
  41#define SYS_DMA                 0x064
  42#define SYS_PROCID0             0x084
  43#define SYS_PROCID1             0x088
  44#define SYS_CFGDATA             0x0a0
  45#define SYS_CFGCTRL             0x0a4
  46#define SYS_CFGSTAT             0x0a8
  47
  48#define SYS_HBI_MASK            0xfff
  49#define SYS_ID_HBI_SHIFT        16
  50#define SYS_PROCIDx_HBI_SHIFT   0
  51
  52#define SYS_MCI_CARDIN          (1 << 0)
  53#define SYS_MCI_WPROT           (1 << 1)
  54
  55#define SYS_FLASH_WPn           (1 << 0)
  56
  57#define SYS_MISC_MASTERSITE     (1 << 14)
  58
  59#define SYS_CFGCTRL_START       (1 << 31)
  60#define SYS_CFGCTRL_WRITE       (1 << 30)
  61#define SYS_CFGCTRL_DCC(n)      (((n) & 0xf) << 26)
  62#define SYS_CFGCTRL_FUNC(n)     (((n) & 0x3f) << 20)
  63#define SYS_CFGCTRL_SITE(n)     (((n) & 0x3) << 16)
  64#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
  65#define SYS_CFGCTRL_DEVICE(n)   (((n) & 0xfff) << 0)
  66
  67#define SYS_CFGSTAT_ERR         (1 << 1)
  68#define SYS_CFGSTAT_COMPLETE    (1 << 0)
  69
  70
  71static void __iomem *vexpress_sysreg_base;
  72static struct device *vexpress_sysreg_dev;
  73static int vexpress_master_site;
  74
  75
  76void vexpress_flags_set(u32 data)
  77{
  78        writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
  79        writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
  80}
  81
  82u32 vexpress_get_procid(int site)
  83{
  84        if (site == VEXPRESS_SITE_MASTER)
  85                site = vexpress_master_site;
  86
  87        return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
  88                        SYS_PROCID0 : SYS_PROCID1));
  89}
  90
  91u32 vexpress_get_hbi(int site)
  92{
  93        u32 id;
  94
  95        switch (site) {
  96        case VEXPRESS_SITE_MB:
  97                id = readl(vexpress_sysreg_base + SYS_ID);
  98                return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
  99        case VEXPRESS_SITE_MASTER:
 100        case VEXPRESS_SITE_DB1:
 101        case VEXPRESS_SITE_DB2:
 102                id = vexpress_get_procid(site);
 103                return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
 104        }
 105
 106        return ~0;
 107}
 108
 109void __iomem *vexpress_get_24mhz_clock_base(void)
 110{
 111        return vexpress_sysreg_base + SYS_24MHZ;
 112}
 113
 114
 115static void vexpress_sysreg_find_prop(struct device_node *node,
 116                const char *name, u32 *val)
 117{
 118        of_node_get(node);
 119        while (node) {
 120                if (of_property_read_u32(node, name, val) == 0) {
 121                        of_node_put(node);
 122                        return;
 123                }
 124                node = of_get_next_parent(node);
 125        }
 126}
 127
 128unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
 129{
 130        u32 site = 0;
 131
 132        WARN_ON(dev && node && dev->of_node != node);
 133        if (dev && !node)
 134                node = dev->of_node;
 135
 136        if (node) {
 137                vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
 138        } else if (dev && dev->bus == &platform_bus_type) {
 139                struct platform_device *pdev = to_platform_device(dev);
 140
 141                if (pdev->num_resources == 1 &&
 142                                pdev->resource[0].flags == IORESOURCE_BUS)
 143                        site = pdev->resource[0].start;
 144        } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
 145                site = VEXPRESS_SITE_MASTER;
 146        }
 147
 148        if (site == VEXPRESS_SITE_MASTER)
 149                site = vexpress_master_site;
 150
 151        return site;
 152}
 153
 154
 155struct vexpress_sysreg_config_func {
 156        u32 template;
 157        u32 device;
 158};
 159
 160static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
 161static struct timer_list vexpress_sysreg_config_timer;
 162static u32 *vexpress_sysreg_config_data;
 163static int vexpress_sysreg_config_tries;
 164
 165static void *vexpress_sysreg_config_func_get(struct device *dev,
 166                struct device_node *node)
 167{
 168        struct vexpress_sysreg_config_func *config_func;
 169        u32 site;
 170        u32 position = 0;
 171        u32 dcc = 0;
 172        u32 func_device[2];
 173        int err = -EFAULT;
 174
 175        if (node) {
 176                of_node_get(node);
 177                vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
 178                vexpress_sysreg_find_prop(node, "arm,vexpress,position",
 179                                &position);
 180                vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
 181                err = of_property_read_u32_array(node,
 182                                "arm,vexpress-sysreg,func", func_device,
 183                                ARRAY_SIZE(func_device));
 184                of_node_put(node);
 185        } else if (dev && dev->bus == &platform_bus_type) {
 186                struct platform_device *pdev = to_platform_device(dev);
 187
 188                if (pdev->num_resources == 1 &&
 189                                pdev->resource[0].flags == IORESOURCE_BUS) {
 190                        site = pdev->resource[0].start;
 191                        func_device[0] = pdev->resource[0].end;
 192                        func_device[1] = pdev->id;
 193                        err = 0;
 194                }
 195        }
 196        if (err)
 197                return NULL;
 198
 199        config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
 200        if (!config_func)
 201                return NULL;
 202
 203        config_func->template = SYS_CFGCTRL_DCC(dcc);
 204        config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
 205        config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
 206                        vexpress_master_site : site);
 207        config_func->template |= SYS_CFGCTRL_POSITION(position);
 208        config_func->device |= func_device[1];
 209
 210        dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
 211                        config_func->template, config_func->device);
 212
 213        return config_func;
 214}
 215
 216static void vexpress_sysreg_config_func_put(void *func)
 217{
 218        kfree(func);
 219}
 220
 221static int vexpress_sysreg_config_func_exec(void *func, int offset,
 222                bool write, u32 *data)
 223{
 224        int status;
 225        struct vexpress_sysreg_config_func *config_func = func;
 226        u32 command;
 227
 228        if (WARN_ON(!vexpress_sysreg_base))
 229                return -ENOENT;
 230
 231        command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
 232        if (WARN_ON(command & SYS_CFGCTRL_START))
 233                return -EBUSY;
 234
 235        command = SYS_CFGCTRL_START;
 236        command |= write ? SYS_CFGCTRL_WRITE : 0;
 237        command |= config_func->template;
 238        command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
 239
 240        /* Use a canary for reads */
 241        if (!write)
 242                *data = 0xdeadbeef;
 243
 244        dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n",
 245                        command, *data);
 246        writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
 247        writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
 248        writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
 249        mb();
 250
 251        if (vexpress_sysreg_dev) {
 252                /* Schedule completion check */
 253                if (!write)
 254                        vexpress_sysreg_config_data = data;
 255                vexpress_sysreg_config_tries = 100;
 256                mod_timer(&vexpress_sysreg_config_timer,
 257                                jiffies + usecs_to_jiffies(100));
 258                status = VEXPRESS_CONFIG_STATUS_WAIT;
 259        } else {
 260                /* Early execution, no timer available, have to spin */
 261                u32 cfgstat;
 262
 263                do {
 264                        cpu_relax();
 265                        cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
 266                } while (!cfgstat);
 267
 268                if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE))
 269                        *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
 270                status = VEXPRESS_CONFIG_STATUS_DONE;
 271
 272                if (cfgstat & SYS_CFGSTAT_ERR)
 273                        status = -EINVAL;
 274        }
 275
 276        return status;
 277}
 278
 279struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
 280        .name = "vexpress-sysreg",
 281        .func_get = vexpress_sysreg_config_func_get,
 282        .func_put = vexpress_sysreg_config_func_put,
 283        .func_exec = vexpress_sysreg_config_func_exec,
 284};
 285
 286static void vexpress_sysreg_config_complete(unsigned long data)
 287{
 288        int status = VEXPRESS_CONFIG_STATUS_DONE;
 289        u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
 290
 291        if (cfgstat & SYS_CFGSTAT_ERR)
 292                status = -EINVAL;
 293        if (!vexpress_sysreg_config_tries--)
 294                status = -ETIMEDOUT;
 295
 296        if (status < 0) {
 297                dev_err(vexpress_sysreg_dev, "error %d\n", status);
 298        } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) {
 299                mod_timer(&vexpress_sysreg_config_timer,
 300                                jiffies + usecs_to_jiffies(50));
 301                return;
 302        }
 303
 304        if (vexpress_sysreg_config_data) {
 305                *vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
 306                                SYS_CFGDATA);
 307                dev_dbg(vexpress_sysreg_dev, "read data %x\n",
 308                                *vexpress_sysreg_config_data);
 309                vexpress_sysreg_config_data = NULL;
 310        }
 311
 312        vexpress_config_complete(vexpress_sysreg_config_bridge, status);
 313}
 314
 315
 316void __init vexpress_sysreg_setup(struct device_node *node)
 317{
 318        if (WARN_ON(!vexpress_sysreg_base))
 319                return;
 320
 321        if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
 322                vexpress_master_site = VEXPRESS_SITE_DB2;
 323        else
 324                vexpress_master_site = VEXPRESS_SITE_DB1;
 325
 326        vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
 327                        node, &vexpress_sysreg_config_bridge_info);
 328        WARN_ON(!vexpress_sysreg_config_bridge);
 329}
 330
 331void __init vexpress_sysreg_early_init(void __iomem *base)
 332{
 333        vexpress_sysreg_base = base;
 334        vexpress_sysreg_setup(NULL);
 335}
 336
 337void __init vexpress_sysreg_of_early_init(void)
 338{
 339        struct device_node *node = of_find_compatible_node(NULL, NULL,
 340                        "arm,vexpress-sysreg");
 341
 342        if (node) {
 343                vexpress_sysreg_base = of_iomap(node, 0);
 344                vexpress_sysreg_setup(node);
 345        } else {
 346                pr_info("vexpress-sysreg: No Device Tree node found.");
 347        }
 348}
 349
 350
 351static struct vexpress_sysreg_gpio {
 352        unsigned long reg;
 353        u32 value;
 354} vexpress_sysreg_gpios[] = {
 355        [VEXPRESS_GPIO_MMC_CARDIN] = {
 356                .reg = SYS_MCI,
 357                .value = SYS_MCI_CARDIN,
 358        },
 359        [VEXPRESS_GPIO_MMC_WPROT] = {
 360                .reg = SYS_MCI,
 361                .value = SYS_MCI_WPROT,
 362        },
 363        [VEXPRESS_GPIO_FLASH_WPn] = {
 364                .reg = SYS_FLASH,
 365                .value = SYS_FLASH_WPn,
 366        },
 367};
 368
 369static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
 370                                       unsigned offset)
 371{
 372        return 0;
 373}
 374
 375static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
 376                                                unsigned offset, int value)
 377{
 378        return 0;
 379}
 380
 381static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
 382                                       unsigned offset)
 383{
 384        struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
 385        u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
 386
 387        return !!(reg_value & gpio->value);
 388}
 389
 390static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
 391                                       unsigned offset, int value)
 392{
 393        struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
 394        u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
 395
 396        if (value)
 397                reg_value |= gpio->value;
 398        else
 399                reg_value &= ~gpio->value;
 400
 401        writel(reg_value, vexpress_sysreg_base + gpio->reg);
 402}
 403
 404static struct gpio_chip vexpress_sysreg_gpio_chip = {
 405        .label = "vexpress-sysreg",
 406        .direction_input = vexpress_sysreg_gpio_direction_input,
 407        .direction_output = vexpress_sysreg_gpio_direction_output,
 408        .get = vexpress_sysreg_gpio_get,
 409        .set = vexpress_sysreg_gpio_set,
 410        .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
 411        .base = 0,
 412};
 413
 414
 415static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
 416                struct device_attribute *attr, char *buf)
 417{
 418        return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
 419}
 420
 421DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
 422
 423static int vexpress_sysreg_probe(struct platform_device *pdev)
 424{
 425        int err;
 426        struct resource *res = platform_get_resource(pdev,
 427                        IORESOURCE_MEM, 0);
 428
 429        if (!devm_request_mem_region(&pdev->dev, res->start,
 430                        resource_size(res), pdev->name)) {
 431                dev_err(&pdev->dev, "Failed to request memory region!\n");
 432                return -EBUSY;
 433        }
 434
 435        if (!vexpress_sysreg_base) {
 436                vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
 437                                resource_size(res));
 438                vexpress_sysreg_setup(pdev->dev.of_node);
 439        }
 440
 441        if (!vexpress_sysreg_base) {
 442                dev_err(&pdev->dev, "Failed to obtain base address!\n");
 443                return -EFAULT;
 444        }
 445
 446        setup_timer(&vexpress_sysreg_config_timer,
 447                        vexpress_sysreg_config_complete, 0);
 448
 449        vexpress_sysreg_gpio_chip.dev = &pdev->dev;
 450        err = gpiochip_add(&vexpress_sysreg_gpio_chip);
 451        if (err) {
 452                vexpress_config_bridge_unregister(
 453                                vexpress_sysreg_config_bridge);
 454                dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
 455                                err);
 456                return err;
 457        }
 458
 459        vexpress_sysreg_dev = &pdev->dev;
 460
 461        device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
 462
 463        return 0;
 464}
 465
 466static const struct of_device_id vexpress_sysreg_match[] = {
 467        { .compatible = "arm,vexpress-sysreg", },
 468        {},
 469};
 470
 471static struct platform_driver vexpress_sysreg_driver = {
 472        .driver = {
 473                .name = "vexpress-sysreg",
 474                .of_match_table = vexpress_sysreg_match,
 475        },
 476        .probe = vexpress_sysreg_probe,
 477};
 478
 479static int __init vexpress_sysreg_init(void)
 480{
 481        return platform_driver_register(&vexpress_sysreg_driver);
 482}
 483core_initcall(vexpress_sysreg_init);
 484
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.