1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2018 4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc 5 */ 6 7#include <common.h> 8#include <axi.h> 9#include <dm.h> 10#include <log.h> 11#include <malloc.h> 12 13/** 14 * struct sandbox_store_priv - Private data structure of a AXI store device 15 * @store: The buffer holding the device's internal memory, which is read from 16 * and written to using the driver's methods 17 */ 18struct sandbox_store_priv { 19 u8 *store; 20}; 21 22/** 23 * copy_axi_data() - Copy data from source to destination with a given AXI 24 * transfer width 25 * @src: Pointer to the data source from where data will be read 26 * @dst: Pointer to the data destination where data will be written to 27 * @size: Size of the data to be copied given by a axi_size_t enum value 28 * 29 * Return: 0 if OK, -ve on error 30 */ 31static int copy_axi_data(void *src, void *dst, enum axi_size_t size) 32{ 33 switch (size) { 34 case AXI_SIZE_8: 35 *((u8 *)dst) = *((u8 *)src); 36 return 0; 37 case AXI_SIZE_16: 38 *((u16 *)dst) = be16_to_cpu(*((u16 *)src)); 39 return 0; 40 case AXI_SIZE_32: 41 *((u32 *)dst) = be32_to_cpu(*((u32 *)src)); 42 return 0; 43 default: 44 debug("%s: Unknown AXI transfer size '%d'\n", __func__, size); 45 return -EINVAL; 46 } 47} 48 49static int sandbox_store_read(struct udevice *dev, ulong address, void *data, 50 enum axi_size_t size) 51{ 52 struct sandbox_store_priv *priv = dev_get_priv(dev); 53 54 return copy_axi_data(priv->store + address, data, size); 55} 56 57static int sandbox_store_write(struct udevice *dev, ulong address, void *data, 58 enum axi_size_t size) 59{ 60 struct sandbox_store_priv *priv = dev_get_priv(dev); 61 62 return copy_axi_data(data, priv->store + address, size); 63} 64 65static int sandbox_store_get_store(struct udevice *dev, u8 **store) 66{ 67 struct sandbox_store_priv *priv = dev_get_priv(dev); 68 69 *store = priv->store; 70 71 return 0; 72} 73 74static const struct udevice_id sandbox_store_ids[] = { 75 { .compatible = "sandbox,sandbox_store" }, 76 { /* sentinel */ } 77}; 78 79static const struct axi_emul_ops sandbox_store_ops = { 80 .read = sandbox_store_read, 81 .write = sandbox_store_write, 82 .get_store = sandbox_store_get_store, 83}; 84 85static int sandbox_store_probe(struct udevice *dev) 86{ 87 struct sandbox_store_priv *priv = dev_get_priv(dev); 88 u32 reg[2]; 89 int ret; 90 91 ret = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg)); 92 if (ret) { 93 debug("%s: Could not read 'reg' property\n", dev->name); 94 return -EINVAL; 95 } 96 97 /* 98 * Allocate the device's internal storage that will be read 99 * from/written to 100 */ 101 priv->store = calloc(reg[1], 1); 102 if (!priv->store) 103 return -ENOMEM; 104 105 return 0; 106} 107 108static int sandbox_store_remove(struct udevice *dev) 109{ 110 struct sandbox_store_priv *priv = dev_get_priv(dev); 111 112 free(priv->store); 113 114 return 0; 115} 116 117U_BOOT_DRIVER(sandbox_axi_store) = { 118 .name = "sandbox_axi_store", 119 .id = UCLASS_AXI_EMUL, 120 .of_match = sandbox_store_ids, 121 .ops = &sandbox_store_ops, 122 .priv_auto = sizeof(struct sandbox_store_priv), 123 .probe = sandbox_store_probe, 124 .remove = sandbox_store_remove, 125}; 126