summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2010-11-18 13:55:30 +0100
committerTobias Klauser <tklauser@distanz.ch>2010-11-18 13:55:30 +0100
commit498763e178b5d8f51c17057630779cd48393e6f6 (patch)
tree4937a7e8b76898e150fce43b69ca8bcd9aa05a92
parent105d2c8f1436a91867ce352144baae5c390a32e1 (diff)
Generic device handling updates
-rw-r--r--device.c70
-rw-r--r--device.h33
2 files changed, 101 insertions, 2 deletions
diff --git a/device.c b/device.c
index 249d778..bec5a1a 100644
--- a/device.c
+++ b/device.c
@@ -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);
+}
diff --git a/device.h b/device.h
index beabe52..cf84e05 100644
--- a/device.h
+++ b/device.h
@@ -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_ */