diff options
-rw-r--r-- | device.c | 70 | ||||
-rw-r--r-- | device.h | 33 |
2 files changed, 101 insertions, 2 deletions
@@ -22,6 +22,14 @@ static struct device *devices[] = { }; #define DEVICES_COUNT ARRAY_SIZE(devices) +bool device_generic_is_dev_addr(struct device *dev, uint32_t addr) +{ + if (addr >= dev->base && addr < dev->base + dev->size) + return true; + + return false; +} + int device_init_all(void) { unsigned int i; @@ -30,7 +38,7 @@ int device_init_all(void) for (i = 0; i < DEVICES_COUNT; i++) { struct device *dev = devices[i]; - if (dev->init == NULL) + if (unlikely(dev->init == NULL)) continue; ret = dev->init(dev); @@ -39,8 +47,66 @@ int device_init_all(void) break; } - vinfo("%s at 0x%08x\n", dev->name, dev->base); + if (dev->is_dev_addr == NULL) + dev->is_dev_addr = device_generic_is_dev_addr; + + vinfo("%s at 0x%08x - 0x%08x\n", dev->name, dev->base, + (uint32_t)(dev->base + dev->size)); } return ret; } + +/** + * Get device mapped at a specific address. + * + * @param addr address to get the mapped device for + * @return pointer to the device mapped at addr, NULL if no device is + * mapped there + */ +struct device *device_get_by_addr(uint32_t addr) +{ + unsigned int i; + struct device *dev = NULL; + + for (i = 0; i < DEVICES_COUNT; i++) { + dev = devices[i]; + if (unlikely(dev->is_dev_addr == NULL)) + continue; + if (dev->is_dev_addr(dev, addr)) + return dev; + } + + return NULL; +} + +void device_simulate_all(void) +{ + unsigned int i; + struct device *dev; + + for (i = 0; i < DEVICES_COUNT; i++) { + dev = devices[i]; + if (likely(dev->simulate != NULL)) + dev->simulate(dev); + } +} + +void io_register_init(struct io_register *reg, uint32_t addr, + uint32_t valid, uint32_t readonly, uint32_t value) +{ + reg->addr = addr; + reg->valid_mask = valid; + reg->readonly_mask = readonly; + reg->value = value; +} + +uint32_t io_register_read(struct io_register *reg) +{ + return reg->value & reg->valid_mask; +} + +void io_register_write(struct io_register *reg, uint32_t value) +{ + reg->value = value & ~(reg->readonly_mask); +} @@ -12,20 +12,53 @@ #ifndef _DEVICE_H_ #define _DEVICE_H_ +/* IRQs for all used devices shall be allocated here */ +#define IRQ_TIMER 1 +#define IRQ_UART 2 +#define IRQ_JTAG_UART 3 + +#define IRQ_TO_MASK(irq) (1UL << (irq)) + struct device { const char *name; uint32_t base; size_t size; + uint32_t irq_mask; + int (*init)(struct device *dev); bool (*is_dev_addr)(struct device *dev, uint32_t addr); + size_t (*read)(struct device *dev, uint32_t addr, uint32_t *data, size_t count); + size_t (*write)(struct device *dev, uint32_t addr, uint32_t *data, size_t count); + bool (*has_irq)(struct device *dev); void (*simulate)(struct device *dev); /* Private data */ void *priv; }; +extern bool device_generic_is_dev_addr(struct device *dev, uint32_t addr); extern int device_init_all(void); +extern struct device *device_get_by_addr(uint32_t addr); +extern void device_simulate_all(void); + +/* + * Device registers + */ + +struct io_register { + uint32_t addr; + uint32_t valid_mask; + uint32_t readonly_mask; + uint32_t value; +}; + +#define REG_TO_OFF(reg) ((reg) * sizeof(uint32_t)) + +extern void io_register_init(struct io_register *reg, uint32_t addr, + uint32_t valid, uint32_t readonly, uint32_t value); +extern uint32_t io_register_read(struct io_register *reg); +extern void io_register_write(struct io_register *reg, uint32_t value); #endif /* _DEVICE_H_ */ |