uboot/drivers/misc/p2sb-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Uclass for Primary-to-sideband bus, used to access various peripherals
   4 *
   5 * Copyright 2019 Google LLC
   6 * Written by Simon Glass <sjg@chromium.org>
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <mapmem.h>
  14#include <p2sb.h>
  15#include <spl.h>
  16#include <asm/io.h>
  17#include <dm/uclass-internal.h>
  18
  19#define PCR_COMMON_IOSF_1_0     1
  20
  21int p2sb_set_hide(struct udevice *dev, bool hide)
  22{
  23        struct p2sb_ops *ops = p2sb_get_ops(dev);
  24
  25        if (!ops->set_hide)
  26                return -ENOSYS;
  27
  28        return ops->set_hide(dev, hide);
  29}
  30
  31void *pcr_reg_address(struct udevice *dev, uint offset)
  32{
  33        struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
  34        struct udevice *p2sb = dev_get_parent(dev);
  35        struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
  36        uintptr_t reg_addr;
  37
  38        /* Create an address based off of port id and offset */
  39        reg_addr = upriv->mmio_base;
  40        reg_addr += pplat->pid << PCR_PORTID_SHIFT;
  41        reg_addr += offset;
  42
  43        return map_sysmem(reg_addr, 4);
  44}
  45
  46/*
  47 * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
  48 * agents are using 32-bit aligned accesses for their configuration
  49 * registers. For IOSF versions greater than 1_0, IOSF-SB
  50 * agents can use any access (8/16/32 bit aligned) for their
  51 * configuration registers
  52 */
  53static inline void check_pcr_offset_align(uint offset, uint size)
  54{
  55        const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
  56
  57        assert(IS_ALIGNED(offset, align));
  58}
  59
  60uint pcr_read32(struct udevice *dev, uint offset)
  61{
  62        void *ptr;
  63        uint val;
  64
  65        /* Ensure the PCR offset is correctly aligned */
  66        assert(IS_ALIGNED(offset, sizeof(uint32_t)));
  67
  68        ptr = pcr_reg_address(dev, offset);
  69        val = readl(ptr);
  70        unmap_sysmem(ptr);
  71
  72        return val;
  73}
  74
  75uint pcr_read16(struct udevice *dev, uint offset)
  76{
  77        /* Ensure the PCR offset is correctly aligned */
  78        check_pcr_offset_align(offset, sizeof(uint16_t));
  79
  80        return readw(pcr_reg_address(dev, offset));
  81}
  82
  83uint pcr_read8(struct udevice *dev, uint offset)
  84{
  85        /* Ensure the PCR offset is correctly aligned */
  86        check_pcr_offset_align(offset, sizeof(uint8_t));
  87
  88        return readb(pcr_reg_address(dev, offset));
  89}
  90
  91/*
  92 * After every write one needs to perform a read an innocuous register to
  93 * ensure the writes are completed for certain ports. This is done for
  94 * all ports so that the callers don't need the per-port knowledge for
  95 * each transaction.
  96 */
  97static void write_completion(struct udevice *dev, uint offset)
  98{
  99        readl(pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
 100}
 101
 102void pcr_write32(struct udevice *dev, uint offset, uint indata)
 103{
 104        /* Ensure the PCR offset is correctly aligned */
 105        assert(IS_ALIGNED(offset, sizeof(indata)));
 106
 107        writel(indata, pcr_reg_address(dev, offset));
 108        /* Ensure the writes complete */
 109        write_completion(dev, offset);
 110}
 111
 112void pcr_write16(struct udevice *dev, uint offset, uint indata)
 113{
 114        /* Ensure the PCR offset is correctly aligned */
 115        check_pcr_offset_align(offset, sizeof(uint16_t));
 116
 117        writew(indata, pcr_reg_address(dev, offset));
 118        /* Ensure the writes complete */
 119        write_completion(dev, offset);
 120}
 121
 122void pcr_write8(struct udevice *dev, uint offset, uint indata)
 123{
 124        /* Ensure the PCR offset is correctly aligned */
 125        check_pcr_offset_align(offset, sizeof(uint8_t));
 126
 127        writeb(indata, pcr_reg_address(dev, offset));
 128        /* Ensure the writes complete */
 129        write_completion(dev, offset);
 130}
 131
 132void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set)
 133{
 134        uint data32;
 135
 136        data32 = pcr_read32(dev, offset);
 137        data32 &= ~clr;
 138        data32 |= set;
 139        pcr_write32(dev, offset, data32);
 140}
 141
 142void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set)
 143{
 144        uint data16;
 145
 146        data16 = pcr_read16(dev, offset);
 147        data16 &= ~clr;
 148        data16 |= set;
 149        pcr_write16(dev, offset, data16);
 150}
 151
 152void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set)
 153{
 154        uint data8;
 155
 156        data8 = pcr_read8(dev, offset);
 157        data8 &= ~clr;
 158        data8 |= set;
 159        pcr_write8(dev, offset, data8);
 160}
 161
 162int p2sb_get_port_id(struct udevice *dev)
 163{
 164        struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
 165
 166        return pplat->pid;
 167}
 168
 169int p2sb_set_port_id(struct udevice *dev, int portid)
 170{
 171        struct udevice *ps2b;
 172        struct p2sb_child_platdata *pplat;
 173
 174        if (!CONFIG_IS_ENABLED(OF_PLATDATA))
 175                return -ENOSYS;
 176
 177        if (!CONFIG_IS_ENABLED(OF_PLATDATA_PARENT)) {
 178                uclass_find_first_device(UCLASS_P2SB, &ps2b);
 179                if (!ps2b)
 180                        return -EDEADLK;
 181                dev->parent = ps2b;
 182
 183                /*
 184                 * We must allocate this, since when the device was bound it did
 185                 * not have a parent.
 186                 */
 187                dev->parent_platdata = malloc(sizeof(*pplat));
 188                if (!dev->parent_platdata)
 189                        return -ENOMEM;
 190        }
 191        pplat = dev_get_parent_platdata(dev);
 192        pplat->pid = portid;
 193
 194        return 0;
 195}
 196
 197static int p2sb_child_post_bind(struct udevice *dev)
 198{
 199#if !CONFIG_IS_ENABLED(OF_PLATDATA)
 200        struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
 201        int ret;
 202        u32 pid;
 203
 204        ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
 205        if (ret)
 206                return ret;
 207        pplat->pid = pid;
 208#endif
 209
 210        return 0;
 211}
 212
 213static int p2sb_post_bind(struct udevice *dev)
 214{
 215        if (spl_phase() > PHASE_TPL && !CONFIG_IS_ENABLED(OF_PLATDATA))
 216                return dm_scan_fdt_dev(dev);
 217
 218        return 0;
 219}
 220
 221UCLASS_DRIVER(p2sb) = {
 222        .id             = UCLASS_P2SB,
 223        .name           = "p2sb",
 224        .per_device_auto_alloc_size = sizeof(struct p2sb_uc_priv),
 225        .post_bind      = p2sb_post_bind,
 226        .child_post_bind = p2sb_child_post_bind,
 227        .per_child_platdata_auto_alloc_size =
 228                sizeof(struct p2sb_child_platdata),
 229};
 230