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_LED_LED(n)          (1 << (n))
  53
  54#define SYS_MCI_CARDIN          (1 << 0)
  55#define SYS_MCI_WPROT           (1 << 1)
  56
  57#define SYS_FLASH_WPn           (1 << 0)
  58
  59#define SYS_MISC_MASTERSITE     (1 << 14)
  60
  61#define SYS_CFGCTRL_START       (1 << 31)
  62#define SYS_CFGCTRL_WRITE       (1 << 30)
  63#define SYS_CFGCTRL_DCC(n)      (((n) & 0xf) << 26)
  64#define SYS_CFGCTRL_FUNC(n)     (((n) & 0x3f) << 20)
  65#define SYS_CFGCTRL_SITE(n)     (((n) & 0x3) << 16)
  66#define SYS_CFGCTRL_POSITION(n) (((n) & 0xf) << 12)
  67#define SYS_CFGCTRL_DEVICE(n)   (((n) & 0xfff) << 0)
  68
  69#define SYS_CFGSTAT_ERR         (1 << 1)
  70#define SYS_CFGSTAT_COMPLETE    (1 << 0)
  71
  72
  73static void __iomem *vexpress_sysreg_base;
  74static struct device *vexpress_sysreg_dev;
  75static int vexpress_master_site;
  76
  77
  78void vexpress_flags_set(u32 data)
  79{
  80        writel(~0, vexpress_sysreg_base + SYS_FLAGSCLR);
  81        writel(data, vexpress_sysreg_base + SYS_FLAGSSET);
  82}
  83
  84u32 vexpress_get_procid(int site)
  85{
  86        if (site == VEXPRESS_SITE_MASTER)
  87                site = vexpress_master_site;
  88
  89        return readl(vexpress_sysreg_base + (site == VEXPRESS_SITE_DB1 ?
  90                        SYS_PROCID0 : SYS_PROCID1));
  91}
  92
  93u32 vexpress_get_hbi(int site)
  94{
  95        u32 id;
  96
  97        switch (site) {
  98        case VEXPRESS_SITE_MB:
  99                id = readl(vexpress_sysreg_base + SYS_ID);
 100                return (id >> SYS_ID_HBI_SHIFT) & SYS_HBI_MASK;
 101        case VEXPRESS_SITE_MASTER:
 102        case VEXPRESS_SITE_DB1:
 103        case VEXPRESS_SITE_DB2:
 104                id = vexpress_get_procid(site);
 105                return (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
 106        }
 107
 108        return ~0;
 109}
 110
 111void __iomem *vexpress_get_24mhz_clock_base(void)
 112{
 113        return vexpress_sysreg_base + SYS_24MHZ;
 114}
 115
 116
 117static void vexpress_sysreg_find_prop(struct device_node *node,
 118                const char *name, u32 *val)
 119{
 120        of_node_get(node);
 121        while (node) {
 122                if (of_property_read_u32(node, name, val) == 0) {
 123                        of_node_put(node);
 124                        return;
 125                }
 126                node = of_get_next_parent(node);
 127        }
 128}
 129
 130unsigned __vexpress_get_site(struct device *dev, struct device_node *node)
 131{
 132        u32 site = 0;
 133
 134        WARN_ON(dev && node && dev->of_node != node);
 135        if (dev && !node)
 136                node = dev->of_node;
 137
 138        if (node) {
 139                vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
 140        } else if (dev && dev->bus == &platform_bus_type) {
 141                struct platform_device *pdev = to_platform_device(dev);
 142
 143                if (pdev->num_resources == 1 &&
 144                                pdev->resource[0].flags == IORESOURCE_BUS)
 145                        site = pdev->resource[0].start;
 146        } else if (dev && strncmp(dev_name(dev), "ct:", 3) == 0) {
 147                site = VEXPRESS_SITE_MASTER;
 148        }
 149
 150        if (site == VEXPRESS_SITE_MASTER)
 151                site = vexpress_master_site;
 152
 153        return site;
 154}
 155
 156
 157struct vexpress_sysreg_config_func {
 158        u32 template;
 159        u32 device;
 160};
 161
 162static struct vexpress_config_bridge *vexpress_sysreg_config_bridge;
 163static struct timer_list vexpress_sysreg_config_timer;
 164static u32 *vexpress_sysreg_config_data;
 165static int vexpress_sysreg_config_tries;
 166
 167static void *vexpress_sysreg_config_func_get(struct device *dev,
 168                struct device_node *node)
 169{
 170        struct vexpress_sysreg_config_func *config_func;
 171        u32 site;
 172        u32 position = 0;
 173        u32 dcc = 0;
 174        u32 func_device[2];
 175        int err = -EFAULT;
 176
 177        if (node) {
 178                of_node_get(node);
 179                vexpress_sysreg_find_prop(node, "arm,vexpress,site", &site);
 180                vexpress_sysreg_find_prop(node, "arm,vexpress,position",
 181                                &position);
 182                vexpress_sysreg_find_prop(node, "arm,vexpress,dcc", &dcc);
 183                err = of_property_read_u32_array(node,
 184                                "arm,vexpress-sysreg,func", func_device,
 185                                ARRAY_SIZE(func_device));
 186                of_node_put(node);
 187        } else if (dev && dev->bus == &platform_bus_type) {
 188                struct platform_device *pdev = to_platform_device(dev);
 189
 190                if (pdev->num_resources == 1 &&
 191                                pdev->resource[0].flags == IORESOURCE_BUS) {
 192                        site = pdev->resource[0].start;
 193                        func_device[0] = pdev->resource[0].end;
 194                        func_device[1] = pdev->id;
 195                        err = 0;
 196                }
 197        }
 198        if (err)
 199                return NULL;
 200
 201        config_func = kzalloc(sizeof(*config_func), GFP_KERNEL);
 202        if (!config_func)
 203                return NULL;
 204
 205        config_func->template = SYS_CFGCTRL_DCC(dcc);
 206        config_func->template |= SYS_CFGCTRL_FUNC(func_device[0]);
 207        config_func->template |= SYS_CFGCTRL_SITE(site == VEXPRESS_SITE_MASTER ?
 208                        vexpress_master_site : site);
 209        config_func->template |= SYS_CFGCTRL_POSITION(position);
 210        config_func->device |= func_device[1];
 211
 212        dev_dbg(vexpress_sysreg_dev, "func 0x%p = 0x%x, %d\n", config_func,
 213                        config_func->template, config_func->device);
 214
 215        return config_func;
 216}
 217
 218static void vexpress_sysreg_config_func_put(void *func)
 219{
 220        kfree(func);
 221}
 222
 223static int vexpress_sysreg_config_func_exec(void *func, int offset,
 224                bool write, u32 *data)
 225{
 226        int status;
 227        struct vexpress_sysreg_config_func *config_func = func;
 228        u32 command;
 229
 230        if (WARN_ON(!vexpress_sysreg_base))
 231                return -ENOENT;
 232
 233        command = readl(vexpress_sysreg_base + SYS_CFGCTRL);
 234        if (WARN_ON(command & SYS_CFGCTRL_START))
 235                return -EBUSY;
 236
 237        command = SYS_CFGCTRL_START;
 238        command |= write ? SYS_CFGCTRL_WRITE : 0;
 239        command |= config_func->template;
 240        command |= SYS_CFGCTRL_DEVICE(config_func->device + offset);
 241
 242        /* Use a canary for reads */
 243        if (!write)
 244                *data = 0xdeadbeef;
 245
 246        dev_dbg(vexpress_sysreg_dev, "command %x, data %x\n",
 247                        command, *data);
 248        writel(*data, vexpress_sysreg_base + SYS_CFGDATA);
 249        writel(0, vexpress_sysreg_base + SYS_CFGSTAT);
 250        writel(command, vexpress_sysreg_base + SYS_CFGCTRL);
 251        mb();
 252
 253        if (vexpress_sysreg_dev) {
 254                /* Schedule completion check */
 255                if (!write)
 256                        vexpress_sysreg_config_data = data;
 257                vexpress_sysreg_config_tries = 100;
 258                mod_timer(&vexpress_sysreg_config_timer,
 259                                jiffies + usecs_to_jiffies(100));
 260                status = VEXPRESS_CONFIG_STATUS_WAIT;
 261        } else {
 262                /* Early execution, no timer available, have to spin */
 263                u32 cfgstat;
 264
 265                do {
 266                        cpu_relax();
 267                        cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
 268                } while (!cfgstat);
 269
 270                if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE))
 271                        *data = readl(vexpress_sysreg_base + SYS_CFGDATA);
 272                status = VEXPRESS_CONFIG_STATUS_DONE;
 273
 274                if (cfgstat & SYS_CFGSTAT_ERR)
 275                        status = -EINVAL;
 276        }
 277
 278        return status;
 279}
 280
 281struct vexpress_config_bridge_info vexpress_sysreg_config_bridge_info = {
 282        .name = "vexpress-sysreg",
 283        .func_get = vexpress_sysreg_config_func_get,
 284        .func_put = vexpress_sysreg_config_func_put,
 285        .func_exec = vexpress_sysreg_config_func_exec,
 286};
 287
 288static void vexpress_sysreg_config_complete(unsigned long data)
 289{
 290        int status = VEXPRESS_CONFIG_STATUS_DONE;
 291        u32 cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT);
 292
 293        if (cfgstat & SYS_CFGSTAT_ERR)
 294                status = -EINVAL;
 295        if (!vexpress_sysreg_config_tries--)
 296                status = -ETIMEDOUT;
 297
 298        if (status < 0) {
 299                dev_err(vexpress_sysreg_dev, "error %d\n", status);
 300        } else if (!(cfgstat & SYS_CFGSTAT_COMPLETE)) {
 301                mod_timer(&vexpress_sysreg_config_timer,
 302                                jiffies + usecs_to_jiffies(50));
 303                return;
 304        }
 305
 306        if (vexpress_sysreg_config_data) {
 307                *vexpress_sysreg_config_data = readl(vexpress_sysreg_base +
 308                                SYS_CFGDATA);
 309                dev_dbg(vexpress_sysreg_dev, "read data %x\n",
 310                                *vexpress_sysreg_config_data);
 311                vexpress_sysreg_config_data = NULL;
 312        }
 313
 314        vexpress_config_complete(vexpress_sysreg_config_bridge, status);
 315}
 316
 317
 318void vexpress_sysreg_setup(struct device_node *node)
 319{
 320        if (WARN_ON(!vexpress_sysreg_base))
 321                return;
 322
 323        if (readl(vexpress_sysreg_base + SYS_MISC) & SYS_MISC_MASTERSITE)
 324                vexpress_master_site = VEXPRESS_SITE_DB2;
 325        else
 326                vexpress_master_site = VEXPRESS_SITE_DB1;
 327
 328        vexpress_sysreg_config_bridge = vexpress_config_bridge_register(
 329                        node, &vexpress_sysreg_config_bridge_info);
 330        WARN_ON(!vexpress_sysreg_config_bridge);
 331}
 332
 333void __init vexpress_sysreg_early_init(void __iomem *base)
 334{
 335        vexpress_sysreg_base = base;
 336        vexpress_sysreg_setup(NULL);
 337}
 338
 339void __init vexpress_sysreg_of_early_init(void)
 340{
 341        struct device_node *node;
 342
 343        if (vexpress_sysreg_base)
 344                return;
 345
 346        node = of_find_compatible_node(NULL, NULL, "arm,vexpress-sysreg");
 347        if (node) {
 348                vexpress_sysreg_base = of_iomap(node, 0);
 349                vexpress_sysreg_setup(node);
 350        }
 351}
 352
 353
 354#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
 355        [VEXPRESS_GPIO_##_name] = { \
 356                .reg = _reg, \
 357                .value = _reg##_##_value, \
 358        }
 359
 360static struct vexpress_sysreg_gpio {
 361        unsigned long reg;
 362        u32 value;
 363} vexpress_sysreg_gpios[] = {
 364        VEXPRESS_SYSREG_GPIO(MMC_CARDIN,        SYS_MCI,        CARDIN),
 365        VEXPRESS_SYSREG_GPIO(MMC_WPROT,         SYS_MCI,        WPROT),
 366        VEXPRESS_SYSREG_GPIO(FLASH_WPn,         SYS_FLASH,      WPn),
 367        VEXPRESS_SYSREG_GPIO(LED0,              SYS_LED,        LED(0)),
 368        VEXPRESS_SYSREG_GPIO(LED1,              SYS_LED,        LED(1)),
 369        VEXPRESS_SYSREG_GPIO(LED2,              SYS_LED,        LED(2)),
 370        VEXPRESS_SYSREG_GPIO(LED3,              SYS_LED,        LED(3)),
 371        VEXPRESS_SYSREG_GPIO(LED4,              SYS_LED,        LED(4)),
 372        VEXPRESS_SYSREG_GPIO(LED5,              SYS_LED,        LED(5)),
 373        VEXPRESS_SYSREG_GPIO(LED6,              SYS_LED,        LED(6)),
 374        VEXPRESS_SYSREG_GPIO(LED7,              SYS_LED,        LED(7)),
 375};
 376
 377static int vexpress_sysreg_gpio_direction_input(struct gpio_chip *chip,
 378                                       unsigned offset)
 379{
 380        return 0;
 381}
 382
 383static int vexpress_sysreg_gpio_get(struct gpio_chip *chip,
 384                                       unsigned offset)
 385{
 386        struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
 387        u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
 388
 389        return !!(reg_value & gpio->value);
 390}
 391
 392static void vexpress_sysreg_gpio_set(struct gpio_chip *chip,
 393                                       unsigned offset, int value)
 394{
 395        struct vexpress_sysreg_gpio *gpio = &vexpress_sysreg_gpios[offset];
 396        u32 reg_value = readl(vexpress_sysreg_base + gpio->reg);
 397
 398        if (value)
 399                reg_value |= gpio->value;
 400        else
 401                reg_value &= ~gpio->value;
 402
 403        writel(reg_value, vexpress_sysreg_base + gpio->reg);
 404}
 405
 406static int vexpress_sysreg_gpio_direction_output(struct gpio_chip *chip,
 407                                                unsigned offset, int value)
 408{
 409        vexpress_sysreg_gpio_set(chip, offset, value);
 410
 411        return 0;
 412}
 413
 414static struct gpio_chip vexpress_sysreg_gpio_chip = {
 415        .label = "vexpress-sysreg",
 416        .direction_input = vexpress_sysreg_gpio_direction_input,
 417        .direction_output = vexpress_sysreg_gpio_direction_output,
 418        .get = vexpress_sysreg_gpio_get,
 419        .set = vexpress_sysreg_gpio_set,
 420        .ngpio = ARRAY_SIZE(vexpress_sysreg_gpios),
 421        .base = 0,
 422};
 423
 424
 425#define VEXPRESS_SYSREG_GREEN_LED(_name, _default_trigger, _gpio) \
 426        { \
 427                .name = "v2m:green:"_name, \
 428                .default_trigger = _default_trigger, \
 429                .gpio = VEXPRESS_GPIO_##_gpio, \
 430        }
 431
 432struct gpio_led vexpress_sysreg_leds[] = {
 433        VEXPRESS_SYSREG_GREEN_LED("user1",      "heartbeat",    LED0),
 434        VEXPRESS_SYSREG_GREEN_LED("user2",      "mmc0",         LED1),
 435        VEXPRESS_SYSREG_GREEN_LED("user3",      "cpu0",         LED2),
 436        VEXPRESS_SYSREG_GREEN_LED("user4",      "cpu1",         LED3),
 437        VEXPRESS_SYSREG_GREEN_LED("user5",      "cpu2",         LED4),
 438        VEXPRESS_SYSREG_GREEN_LED("user6",      "cpu3",         LED5),
 439        VEXPRESS_SYSREG_GREEN_LED("user7",      "cpu4",         LED6),
 440        VEXPRESS_SYSREG_GREEN_LED("user8",      "cpu5",         LED7),
 441};
 442
 443struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
 444        .num_leds = ARRAY_SIZE(vexpress_sysreg_leds),
 445        .leds = vexpress_sysreg_leds,
 446};
 447
 448
 449static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
 450                struct device_attribute *attr, char *buf)
 451{
 452        return sprintf(buf, "0x%08x\n", readl(vexpress_sysreg_base + SYS_ID));
 453}
 454
 455DEVICE_ATTR(sys_id, S_IRUGO, vexpress_sysreg_sys_id_show, NULL);
 456
 457static int vexpress_sysreg_probe(struct platform_device *pdev)
 458{
 459        int err;
 460        struct resource *res = platform_get_resource(pdev,
 461                        IORESOURCE_MEM, 0);
 462
 463        if (!devm_request_mem_region(&pdev->dev, res->start,
 464                        resource_size(res), pdev->name)) {
 465                dev_err(&pdev->dev, "Failed to request memory region!\n");
 466                return -EBUSY;
 467        }
 468
 469        if (!vexpress_sysreg_base) {
 470                vexpress_sysreg_base = devm_ioremap(&pdev->dev, res->start,
 471                                resource_size(res));
 472                vexpress_sysreg_setup(pdev->dev.of_node);
 473        }
 474
 475        if (!vexpress_sysreg_base) {
 476                dev_err(&pdev->dev, "Failed to obtain base address!\n");
 477                return -EFAULT;
 478        }
 479
 480        setup_timer(&vexpress_sysreg_config_timer,
 481                        vexpress_sysreg_config_complete, 0);
 482
 483        vexpress_sysreg_gpio_chip.dev = &pdev->dev;
 484        err = gpiochip_add(&vexpress_sysreg_gpio_chip);
 485        if (err) {
 486                vexpress_config_bridge_unregister(
 487                                vexpress_sysreg_config_bridge);
 488                dev_err(&pdev->dev, "Failed to register GPIO chip! (%d)\n",
 489                                err);
 490                return err;
 491        }
 492
 493        platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
 494                        PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
 495                        sizeof(vexpress_sysreg_leds_pdata));
 496
 497        vexpress_sysreg_dev = &pdev->dev;
 498
 499        device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
 500
 501        return 0;
 502}
 503
 504static const struct of_device_id vexpress_sysreg_match[] = {
 505        { .compatible = "arm,vexpress-sysreg", },
 506        {},
 507};
 508
 509static struct platform_driver vexpress_sysreg_driver = {
 510        .driver = {
 511                .name = "vexpress-sysreg",
 512                .of_match_table = vexpress_sysreg_match,
 513        },
 514        .probe = vexpress_sysreg_probe,
 515};
 516
 517static int __init vexpress_sysreg_init(void)
 518{
 519        vexpress_sysreg_of_early_init();
 520        return platform_driver_register(&vexpress_sysreg_driver);
 521}
 522core_initcall(vexpress_sysreg_init);
 523
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.