uboot/drivers/misc/vexpress_config.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2018 Arm Ltd
   4 * Author: Liviu Dudau <liviu.dudau@foss.arm.com>
   5 *
   6 */
   7#include <common.h>
   8#include <dm.h>
   9#include <dm/read.h>
  10#include <asm/io.h>
  11#include <linux/delay.h>
  12#include <misc.h>
  13
  14#define SYS_CFGDATA             0xa0
  15
  16#define SYS_CFGCTRL             0xa4
  17#define SYS_CFGCTRL_START       BIT(31)
  18#define SYS_CFGCTRL_WRITE       BIT(30)
  19
  20#define SYS_CFGSTAT             0xa8
  21#define SYS_CFGSTAT_ERR         BIT(1)
  22#define SYS_CFGSTAT_COMPLETE    BIT(0)
  23
  24struct vexpress_config_sysreg {
  25        phys_addr_t addr;
  26        u32 site;
  27};
  28
  29static int vexpress_config_exec(struct vexpress_config_sysreg *syscfg,
  30                                bool write, void *buf, int size)
  31{
  32        u32 cmd, status, tries = 100;
  33
  34        cmd = (*(u32 *)buf) | SYS_CFGCTRL_START | (syscfg->site << 16);
  35
  36        if (!write) {
  37                /* write a canary in the data register for reads */
  38                writel(0xdeadbeef, syscfg->addr + SYS_CFGDATA);
  39        } else {
  40                cmd |= SYS_CFGCTRL_WRITE;
  41                writel(((u32 *)buf)[1], syscfg->addr + SYS_CFGDATA);
  42        }
  43        writel(0, syscfg->addr + SYS_CFGSTAT);
  44        writel(cmd, syscfg->addr + SYS_CFGCTRL);
  45
  46        /* completion of command takes ages, go to sleep (150us) */
  47        do {
  48                udelay(150);
  49                status = readl(syscfg->addr + SYS_CFGSTAT);
  50                if (status & SYS_CFGSTAT_ERR)
  51                        return -EFAULT;
  52        } while (--tries && !(status & SYS_CFGSTAT_COMPLETE));
  53
  54        if (!tries)
  55                return -ETIMEDOUT;
  56
  57        if (!write)
  58                (*(u32 *)buf) = readl(syscfg->addr + SYS_CFGDATA);
  59
  60        return 0;
  61}
  62
  63static int vexpress_config_read(struct udevice *dev,
  64                                int offset, void *buf, int size)
  65{
  66        struct vexpress_config_sysreg *priv = dev_get_uclass_priv(dev);
  67
  68        if (size != sizeof(u32))
  69                return -EINVAL;
  70
  71        return vexpress_config_exec(priv, false, buf, size);
  72}
  73
  74static int vexpress_config_write(struct udevice *dev,
  75                                 int offset, const void *buf, int size)
  76{
  77        struct vexpress_config_sysreg *priv = dev_get_uclass_priv(dev);
  78
  79        if (size != sizeof(u32) * 2)
  80                return -EINVAL;
  81
  82        return vexpress_config_exec(priv, true, (void *)buf, size);
  83}
  84
  85static struct misc_ops vexpress_config_ops = {
  86        .read = vexpress_config_read,
  87        .write = vexpress_config_write,
  88};
  89
  90static int vexpress_config_probe(struct udevice *dev)
  91{
  92        struct ofnode_phandle_args args;
  93        struct vexpress_config_sysreg *priv;
  94        const char *prop;
  95        int err, prop_size;
  96
  97        err = dev_read_phandle_with_args(dev, "arm,vexpress,config-bridge",
  98                                         NULL, 0, 0, &args);
  99        if (err)
 100                return err;
 101
 102        prop = ofnode_get_property(args.node, "compatible", &prop_size);
 103        if (!prop || (strncmp(prop, "arm,vexpress-sysreg", 19) != 0))
 104                return -ENOENT;
 105
 106        priv = calloc(1, sizeof(*priv));
 107        if (!priv)
 108                return -ENOMEM;
 109
 110        dev->uclass_priv = priv;
 111        priv->addr = ofnode_get_addr(args.node);
 112
 113        return dev_read_u32(dev, "arm,vexpress,site", &priv->site);
 114}
 115
 116static const struct udevice_id vexpress_config_ids[] = {
 117        { .compatible = "arm,vexpress,config-bus" },
 118        { }
 119};
 120
 121U_BOOT_DRIVER(vexpress_config_drv) = {
 122        .name = "vexpress_config_bus",
 123        .id = UCLASS_MISC,
 124        .of_match = vexpress_config_ids,
 125        .bind = dm_scan_fdt_dev,
 126        .probe = vexpress_config_probe,
 127        .ops = &vexpress_config_ops,
 128};
 129