From: John Williams <jwilliams@itee.uq.edu.au>
To: linuxppc-embedded@ozlabs.org, grant.likely@secretlab.ca
Subject: [RFC] SystemACE driver - abstract register ops
Date: Fri, 27 Apr 2007 16:36:31 +1000 [thread overview]
Message-ID: <463199EF.3090900@itee.uq.edu.au> (raw)
[-- Attachment #1: Type: text/plain, Size: 920 bytes --]
Grant,
Thanks for your work on the SystemACE driver - I'll be porting/merging
this across to MicroBlaze very shortly.
Given that SysACE can be hooked up in any number of ways, bit widths,
endians, PPC/Microblaze, can you please offer your comments on the
attached patch?
It introduce a private ace_reg_ops structure, with various member
functions for the different kinds of accesses to the HW.
This patch should not change the functionality of your original driver
at all, it's just groundwork for what's to come.
I recognise that it adds indirection into the various access paths, and
potentially a little bloat. Whether this is better than #if
1...#else...#endif is debatable.
Similar issues will arise for most (all?) of the Xilinx drivers that we
will share between PPC and MicroBlaze. Hopefully we can converge on a
nice consistent and clean way of handling these dual arch drivers.
Cheers,
John
[-- Attachment #2: xsysace-regops.patch --]
[-- Type: text/plain, Size: 5430 bytes --]
Index: linux-2.6.x-petalogix/drivers/block/xsysace.c
===================================================================
--- linux-2.6.x-petalogix/drivers/block/xsysace.c (revision 2628)
+++ linux-2.6.x-petalogix/drivers/block/xsysace.c (working copy)
@@ -73,6 +73,11 @@
* interrupt, then the kernel timer will expire and the driver can
* continue where it left off.
*
+ * SystemACE can be wired up in different endian orders and data widths.
+ * It works on both PPC and MicroBlaze architectures. For this reason,
+ * an ace_reg_ops structure is used that abstracts away low level
+ * endian/width/arch access to the HW registers.
+
* To Do:
* - Add FPGA configuration control interface.
* - Request major number from lanana
@@ -161,32 +166,120 @@
/* ---------------------------------------------------------------------
* Low level register access
*/
+struct reg_ops {
+ u8 (*read8)(void *addr);
+ u16 (*read16)(void *addr);
+ u32 (*read32)(void *addr);
+ u32 (*readdata)(void *addr);
-/* register access macros */
+ void (*write16)(void *addr, u16 val);
+ void (*write32)(void *addr, u32 val);
+ void (*writedata)(void *addr, u32 val);
+};
+
+#define ace_reg_read8(ace, reg) (ace->ops->read8(ace->baseaddr + reg))
+#define ace_reg_read16(ace, reg) (ace->ops->read16(ace->baseaddr + reg))
+#define ace_reg_readdata(ace, reg) (ace->ops->readdata(ace->baseaddr + reg))
+#define ace_reg_read32(ace, reg) (ace->ops->read32(ace->baseaddr+reg))
+#define ace_reg_write16(ace, reg, val) (ace->ops->write16(ace->baseaddr+reg, val))
+#define ace_reg_writedata(ace, reg, val) (ace->ops->writedata(ace->baseaddr + reg, val))
+#define ace_reg_write32(ace, reg, val) (ace->ops->write32(ace->baseaddr+reg, val))
+
+/* register access functions */
#if 1 /* Little endian 16-bit regs */
-#define ace_reg_read8(ace, reg) in_8(ace->baseaddr + reg)
-#define ace_reg_read16(ace, reg) in_le16(ace->baseaddr + reg)
-#define ace_reg_readdata(ace, reg) in_be16(ace->baseaddr + reg)
-#define ace_reg_read32(ace, reg) ((in_le16(ace->baseaddr + reg+2) << 16) | \
- (in_le16(ace->baseaddr + reg)))
-#define ace_reg_write16(ace, reg, val) out_le16(ace->baseaddr + reg, val)
-#define ace_reg_writedata(ace, reg, val) out_be16(ace->baseaddr + reg, val)
-#define ace_reg_write32(ace, reg, val) { \
- out_le16(ace->baseaddr + reg+2, (val) >> 16); \
- out_le16(ace->baseaddr + reg, val); \
- }
+static u8 ace_le16_read8(void *addr)
+{
+ return in_8(addr);
+}
+
+static u16 ace_le16_read16(void *addr)
+{
+ return in_le16(addr);
+}
+
+static u32 ace_le16_read32(void *addr)
+{
+ return ((in_le16(addr+2) << 16) | (in_le16(addr)));
+}
+
+static u32 ace_le16_readdata(void *addr)
+{
+ return in_be16(addr);
+}
+
+static void ace_le16_write16(void *addr, u16 val)
+{
+ out_le16(addr, val);
+}
+
+static void ace_le16_write32(void *addr, u32 val)
+{
+ out_le16(addr+2,(val) >> 16); \
+ out_le16(addr, val);
+}
+
+static void ace_le16_writedata(void *addr, u32 val)
+{
+ out_be16(addr, val);
+}
+
+static struct reg_ops ace_ops = {
+ .read8 = ace_le16_read8,
+ .read16 = ace_le16_read16,
+ .read32 = ace_le16_read32,
+ .readdata = ace_le16_readdata,
+ .write16 = ace_le16_write16,
+ .write32 = ace_le16_write32,
+ .writedata = ace_le16_writedata
+} ;
+
#else /* Big endian 16-bit regs */
-#define ace_reg_read8(ace, reg) in_8(ace->baseaddr + reg)
-#define ace_reg_read16(ace, reg) in_be16(ace->baseaddr + reg)
-#define ace_reg_readdata(ace, reg) in_le16(ace->baseaddr + reg)
-#define ace_reg_read32(ace, reg) ((in_be16(ace->baseaddr + reg+2) << 16) | \
- (in_be16(ace->baseaddr + reg)))
-#define ace_reg_write16(ace, reg, val) out_be16(ace->baseaddr + reg, val)
-#define ace_reg_writedata(ace, reg, val) out_le16(ace->baseaddr + reg, val)
-#define ace_reg_write32(ace, reg, val) { \
- out_be16(ace->baseaddr + reg+2, (val) >> 16); \
- out_be16(ace->baseaddr + reg, val); \
- }
+static u8 ace_be16_read8(void *addr)
+{
+ return in_8(addr);
+}
+
+static u16 ace_be16_read16(void *addr)
+{
+ return in_be16(addr);
+}
+
+static u32 ace_be16_read32(void *addr)
+{
+ return ((in_be16(addr+2) << 16) | (in_be16(addr)));
+}
+
+static u32 ace_be16_readdata(void *addr)
+{
+ return in_le16(addr);
+}
+
+static void ace_be16_write16(void *addr, u16 val)
+{
+ out_be16(addr, val);
+}
+
+static void ace_be16_write32(void *addr, u32 val)
+{
+ out_be16(addr+2,(val) >> 16); \
+ out_be16(addr, val);
+}
+
+static void ace_be16_writedata(void *addr, u32 val)
+{
+ out_le16(addr, val);
+}
+
+static struct reg_ops ace_ops = {
+ .read8 = ace_be16_read8,
+ .read16 = ace_be16_read16,
+ .read32 = ace_be16_read32,
+ .readdata = ace_be16_readdata,
+ .write16 = ace_be16_write16,
+ .write32 = ace_be16_write32,
+ .writedata = ace_be16_writedata
+} ;
+
#endif
struct ace_device {
@@ -222,6 +315,9 @@
int bus_width; /* 0 := 8 bit; 1 := 16 bit */
int lock_count;
+ /* Register access ops */
+ struct reg_ops *ops;
+
/* Block device data structures */
spinlock_t lock;
struct device *dev;
@@ -995,6 +1091,8 @@
ace->id = dev->id;
ace->irq = NO_IRQ;
+ ace->ops=&ace_ops;
+
for (i = 0; i < dev->num_resources; i++) {
if (dev->resource[i].flags & IORESOURCE_MEM)
ace->physaddr = dev->resource[i].start;
next reply other threads:[~2007-04-27 7:59 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-27 6:36 John Williams [this message]
2007-04-27 6:48 ` [RFC] SystemACE driver - abstract register ops Grant Likely
2007-04-27 7:31 ` Grant Likely
2007-04-27 12:11 ` Stefan Roese
2007-04-27 17:30 ` Wolfgang Reissnegger
2007-05-02 13:23 ` Peter Korsgaard
2007-05-02 16:50 ` Wolfgang Reissnegger
2007-04-27 18:38 ` Andrei Konovalov
2007-04-27 18:42 ` Grant Likely
2007-05-01 3:42 ` John Williams
2007-05-01 3:53 ` Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=463199EF.3090900@itee.uq.edu.au \
--to=jwilliams@itee.uq.edu.au \
--cc=grant.likely@secretlab.ca \
--cc=linuxppc-embedded@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).