summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-02-27 22:05:11 +0000
committerAidan MacDonald <amachronic@protonmail.com>2021-03-02 00:36:01 +0000
commit73cee8f17702d0fdc3e0508e8cf7193faae5f015 (patch)
treed83cb08541a2f78f1e7512de7abd0ce788eb8eb5 /utils
parent7418ec5009a0203b562bcf128713ef741815fe0e (diff)
downloadrockbox-73cee8f17702d0fdc3e0508e8cf7193faae5f015.tar.gz
rockbox-73cee8f17702d0fdc3e0508e8cf7193faae5f015.tar.bz2
rockbox-73cee8f17702d0fdc3e0508e8cf7193faae5f015.zip
Add RegGen-NG tool and definitions for Ingenic X1000
Change-Id: Ib9ec35c068e1cff8dcf120a13cfe3f5f58908a95
Diffstat (limited to 'utils')
-rwxr-xr-xutils/reggen-ng/reggen-ng.py465
-rw-r--r--utils/reggen-ng/x1000.reggen742
2 files changed, 1207 insertions, 0 deletions
diff --git a/utils/reggen-ng/reggen-ng.py b/utils/reggen-ng/reggen-ng.py
new file mode 100755
index 0000000000..09549d6fa4
--- /dev/null
+++ b/utils/reggen-ng/reggen-ng.py
@@ -0,0 +1,465 @@
+#!/usr/bin/python3
+#
+# Tool to generate XML files for Rockbox regtools. The syntax is pretty simple
+# and much less verbose than XML; see the '.reggen' files next to this script.
+#
+# Currently this tool expects a 'reggen' file on standard input and writes the
+# equivalent XML to standard output.
+#
+# TODO: document this better and improve the command line usage
+
+from lxml import etree as ET
+from lxml.builder import E
+import functools
+
+class Soc:
+ def __init__(self):
+ self.name = None
+ self.title = None
+ self.desc = None
+ self.isa = None
+ self.version = None
+ self.authors = []
+ self.nodes = []
+
+ def gen(self):
+ node = E("soc", version="2")
+ if self.name is not None:
+ node.append(E("name", self.name))
+ if self.desc is not None:
+ node.append(E("desc", self.desc))
+ if self.isa is not None:
+ node.append(E("isa", self.isa))
+ if self.isa is not None:
+ node.append(E("version", self.version))
+ for a in self.authors:
+ node.append(E("author", a))
+ for n in self.nodes:
+ node.append(n.gen())
+ return node
+
+class Node:
+ def __init__(self, name):
+ self.name = name
+ self.title = None
+ self.desc = None
+ self.instances = []
+ self.children = []
+ self.register_width = None
+ self.fields = []
+
+ def gen(self):
+ node = E("node", E("name", self.name))
+
+ if self.title is not None:
+ node.append(E("title", self.title))
+
+ if self.desc is not None:
+ node.append(E("desc", self.desc))
+
+ for i in self.instances:
+ node.append(i.gen())
+
+ for c in self.children:
+ node.append(c.gen())
+
+ if self.register_width is not None:
+ reg = E("register",
+ E("width", self.register_width))
+ for f in self.fields:
+ reg.append(f.gen())
+ node.append(reg)
+
+ return node
+
+class Instance:
+ def __init__(self, name, addr, stride=None, count=None):
+ self.name = name
+ self.address = addr
+ self.stride = stride
+ self.count = count
+
+ def gen(self):
+ node = E("instance", E("name", self.name))
+
+ if self.stride is not None:
+ node.append(E("range",
+ E("first", "0"),
+ E("count", self.count),
+ E("base", self.address),
+ E("stride", self.stride)))
+ else:
+ node.append(E("address", self.address))
+
+ return node
+
+class Field:
+ def __init__(self, name, msb, lsb):
+ self.name = name
+ self.desc = None
+ self.msb = int(msb)
+ self.lsb = int(lsb)
+ self.enums = []
+
+ def gen(self):
+ node = E("field",
+ E("name", self.name),
+ E("position", "%d" % self.lsb))
+
+ if self.desc is not None:
+ node.append(E("desc", self.desc))
+
+ if self.msb != self.lsb:
+ node.append(E("width", str(self.msb - self.lsb + 1)))
+
+ for n, v in self.enums:
+ node.append(E("enum", E("name", n), E("value", v)))
+
+ return node
+
+class Variant:
+ def __init__(self, ty, offset):
+ self.type = ty
+ self.offset = offset
+
+ def gen(self):
+ return E("variant",
+ E("type", self.type),
+ E("offset", self.offset))
+
+class Parser:
+ def __init__(self, f):
+ self.input = f
+ self.line = 1
+ self.eolstop = False
+ self.next()
+
+ def parse(self):
+ self.skipws()
+ results = self.parse_block_inner({
+ 'name': (self.parse_string, 1),
+ 'title': (self.parse_string, 1),
+ 'desc': (self.parse_string, 1),
+ 'isa': (self.parse_string, 1),
+ 'version': (self.parse_string, 1),
+ 'author': self.parse_string,
+ 'node': self.parse_node,
+ 'reg': self.parse_register,
+ })
+
+ ret = Soc()
+
+ if 'name' in results:
+ ret.name = results['name'][0]
+ else:
+ self.err('missing "name" statement at toplevel')
+
+ if 'title' in results:
+ ret.title = results['title'][0]
+ if 'desc' in results:
+ ret.desc = results['desc'][0]
+ if 'isa' in results:
+ ret.isa = results['isa'][0]
+ if 'version' in results:
+ ret.version = results['version'][0]
+ if 'author' in results:
+ ret.authors += results['author']
+ if 'node' in results:
+ ret.nodes += results['node']
+ if 'reg' in results:
+ ret.nodes += results['reg']
+
+ return ret
+
+ def parse_node(self):
+ name = self.parse_ident()
+ ret, results = self.parse_node_block(name, {
+ 'title': (self.parse_string, 1),
+ 'node': self.parse_node,
+ 'reg': self.parse_register,
+ })
+
+ if 'title' in results:
+ ret.title = results['title'][0]
+ if 'node' in results:
+ ret.children += results['node']
+ if 'reg' in results:
+ ret.children += results['reg']
+
+ return ret
+
+ def parse_register(self):
+ words, has_block = self.parse_wordline(True)
+ name = words[0]
+ width = "32"
+ addr = None
+
+ if len(words) == 1:
+ # reg NAME
+ pass
+ elif len(words) == 2:
+ # reg NAME ADDR
+ addr = words[1]
+ elif len(words) == 3:
+ # reg WIDTH NAME ADDR
+ name = words[1]
+ width = words[0]
+ addr = words[2]
+ else:
+ self.err('malformed register statement')
+
+ if has_block:
+ ret, results = self.parse_node_block(name, {
+ 'field': self.parse_field,
+ 'fld': self.parse_field,
+ 'bit': self.parse_field,
+ 'variant': self.parse_variant,
+ })
+
+ if 'field' in results:
+ ret.fields += results['field']
+ if 'fld' in results:
+ ret.fields += results['fld']
+ if 'bit' in results:
+ ret.fields += results['bit']
+ if 'variant' in results:
+ ret.fields += results['variant']
+ else:
+ ret = Node(name)
+
+ if len(ret.instances) == 0:
+ if addr is None:
+ self.err("no address specified for register")
+ ret.instances.append(Instance(ret.name, addr))
+ elif addr:
+ self.err("duplicate address specification for register")
+
+ ret.register_width = width
+ return ret
+
+ def parse_node_block(self, name, extra_parsers):
+ parsers = {
+ 'desc': (self.parse_string, 1),
+ 'addr': (self.parse_printable, 1),
+ 'instance': functools.partial(self.parse_instance, name),
+ }
+
+ parsers.update(extra_parsers)
+ results = self.parse_block(parsers)
+ ret = Node(name)
+
+ if 'desc' in results:
+ ret.desc = results['desc'][0]
+ if 'addr' in results:
+ ret.instances.append(Instance(ret.name, results['addr'][0]))
+ if 'instance' in results:
+ if 'addr' in results:
+ self.err('instance statement not allowed when addr is given')
+
+ ret.instances += results['instance']
+
+ return ret, results
+
+ def parse_instance(self, default_name):
+ words = self.parse_wordline(False)[0]
+
+ if len(words) == 1:
+ # instance ADDR
+ return Instance(default_name, words[0])
+ elif len(words) == 2:
+ # instance NAME ADDR
+ return Instance(words[0], words[1])
+ elif len(words) == 3:
+ # instance ADDR STRIDE COUNT
+ return Instance(default_name, words[0], words[1], words[2])
+ elif len(words) == 4:
+ # instance NAME ADDR STRIDE COUNT
+ return Instance(words[0], words[1], words[2], words[3])
+ else:
+ self.err('malformed instance statement')
+
+ def parse_field(self):
+ words, has_block = self.parse_wordline(True)
+ name = None
+ msb = None
+ lsb = None
+
+ if len(words) == 2:
+ # field BIT NAME
+ lsb = msb = words[0]
+ name = words[1]
+ elif len(words) == 3:
+ # field MSB LSB NAME
+ msb = words[0]
+ lsb = words[1]
+ name = words[2]
+ else:
+ self.err('malformed field statement')
+
+ try:
+ int(msb)
+ int(lsb)
+ except:
+ self.err('field MSB/LSB must be integers')
+
+ ret = Field(name, msb, lsb)
+ if has_block:
+ results = self.parse_block({
+ 'desc': self.parse_string,
+ 'enum': self.parse_enum,
+ })
+
+ if 'desc' in results:
+ if len(results['desc']) > 1:
+ self.err("only one description allowed")
+ ret.desc = results['desc'][0]
+
+ if 'enum' in results:
+ ret.enums += results['enum']
+
+ return ret
+
+ def parse_wordline(self, allow_block=False):
+ words = []
+ self.eolstop = True
+ while(self.chr != '{' and self.chr != '}' and
+ self.chr != '\n' and self.chr != ';'):
+ words.append(self.parse_printable())
+ self.eolstop = False
+
+ if len(words) == 0:
+ self.err('this type of statement cannot be empty')
+
+ if self.chr == '{':
+ if not allow_block:
+ self.err('this type of statement does not accept blocks')
+ has_block = True
+ else:
+ has_block = False
+ self.skipws()
+
+ return words, has_block
+
+ def parse_variant(self):
+ ty = self.parse_printable()
+ off = self.parse_printable()
+ return Variant(ty, off)
+
+ def parse_enum(self):
+ name = self.parse_printable()
+ value = self.parse_printable()
+ return (name, value)
+
+ def parse_block(self, parsers):
+ if self.chr != '{':
+ self.err("expected '{'")
+ self.next()
+ self.skipws()
+
+ ret = self.parse_block_inner(parsers)
+
+ assert self.chr == '}'
+ self.next()
+ self.skipws()
+ return ret
+
+ def parse_block_inner(self, parsers):
+ ret = {}
+ cnt = {}
+ while self.chr != '}' and self.chr != '\0':
+ kwd = self.parse_ident()
+ if kwd not in parsers:
+ self.err("invalid keyword for block")
+
+ if kwd not in ret:
+ ret[kwd] = []
+ cnt[kwd] = 0
+
+ pentry = parsers[kwd]
+ if type(pentry) is tuple and len(pentry) == 2:
+ pfunc = pentry[0]
+ max_cnt = pentry[1]
+ else:
+ pfunc = pentry
+ max_cnt = 0
+
+ if max_cnt > 0 and cnt[kwd] == max_cnt:
+ if max_cnt == 1:
+ self.err("at most one '%s' statement allowed in this block" % kwd)
+ else:
+ self.err("at most %d '%s' statements allowed in this block" % (max_cnt, kwd))
+
+ ret[kwd].append(pfunc())
+ cnt[kwd] += 1
+
+ return ret
+
+ def parse_ident(self):
+ ident = ''
+ while self.chr.isalnum() or self.chr == '_':
+ ident += self.chr
+ self.next()
+
+ if len(ident) == 0:
+ self.err("expected identifier")
+
+ self.skipws()
+ return ident
+
+ def parse_string(self):
+ if self.chr != '"':
+ self.err("expected string")
+ self.next()
+
+ s = ''
+ while self.chr != '"':
+ s += self.chr
+ self.next()
+ self.next()
+
+ self.skipws()
+ return s
+
+ def parse_printable(self):
+ s = ''
+ while not self.chr.isspace() and self.chr != ';':
+ s += self.chr
+ self.next()
+
+ self.skipws()
+ return s
+
+ def skipws(self):
+ while True:
+ if self.chr == '#':
+ while self.chr != '\n':
+ self.next()
+ if self.eolstop:
+ break
+ self.next()
+ elif self.chr == '\n' or self.chr == ';':
+ if self.eolstop:
+ break
+ self.next()
+ elif self.chr.isspace():
+ self.next()
+ else:
+ break
+
+ def next(self):
+ self.chr = self.input.read(1)
+ if len(self.chr) == 0:
+ self.chr = '\0'
+ if self.chr == '\n':
+ self.line += 1
+ return self.chr
+
+ def err(self, msg):
+ raise ValueError("on line %d: %s" % (self.line, msg))
+
+if __name__ == '__main__':
+ import sys
+ p = Parser(sys.stdin)
+ r = p.parse()
+ print('<?xml version="1.0"?>')
+ ET.dump(r.gen())
diff --git a/utils/reggen-ng/x1000.reggen b/utils/reggen-ng/x1000.reggen
new file mode 100644
index 0000000000..3e5d976a0b
--- /dev/null
+++ b/utils/reggen-ng/x1000.reggen
@@ -0,0 +1,742 @@
+name "x1000"
+title "Ingenic X1000"
+isa "mips"
+version "1.0"
+author "Aidan MacDonald"
+
+node LCD {
+ title "LCD controller"
+ addr 0xb3050000
+
+ reg CFG 0x00 {
+ bit 17 INVDAT
+ }
+
+ reg CTRL 0x30 {
+ fld 30 28 BURST { enum 4WORD 0; enum 8WORD 1; enum 16WORD 2;
+ enum 32WORD 3; enum 64WORD 4; }
+ bit 13 EOFM
+ bit 12 SOFM
+ bit 10 IFUM
+ bit 7 QDM
+ bit 6 BEDN
+ bit 5 PEDN
+ bit 3 ENABLE
+ fld 2 0 BPP {
+ enum 15BIT_OR_16BIT 4
+ enum 18BIT_OR_24BIT 5
+ enum 24BIT_COMPRESSED 6
+ enum 30BIT 7
+ }
+ }
+
+ reg STATE 0x34 {
+ bit 7 QD
+ bit 5 EOF
+ bit 4 SOF
+ bit 2 IFU
+ }
+
+ reg OSDCTRL 0x104
+ reg BGC 0x10c
+ reg DAH 0x10
+ reg DAV 0x14
+ reg VAT 0x0c
+ reg VSYNC 0x04
+ reg HSYNC 0x08
+
+ reg IID 0x38
+ reg DA 0x40
+
+ reg MCFG 0xa0 {
+ # other fields are useless according to Ingenic
+ field 9 8 CWIDTH {
+ enum 16BIT_OR_9BIT 0
+ enum 8BIT 1
+ enum 18BIT 2
+ enum 24BIT 3
+ }
+ }
+
+ reg MCFG_NEW 0xb8 {
+ field 15 13 DWIDTH {
+ enum 8BIT 0
+ enum 9BIT 1
+ enum 16BIT 2
+ enum 18BIT 3
+ enum 24BIT 4
+ }
+
+ field 9 8 DTIMES {
+ enum 1TIME 0
+ enum 2TIME 1
+ enum 3TIME 2
+ }
+
+ bit 11 6800_MODE
+ bit 10 CMD_9BIT
+ bit 5 CSPLY
+ bit 4 RSPLY
+ bit 3 CLKPLY
+ bit 2 DTYPE { enum SERIAL 1; enum PARALLEL 0 }
+ bit 1 CTYPE { enum SERIAL 1; enum PARALLEL 0 }
+ bit 0 FMT_CONV
+ }
+
+ reg MCTRL 0xa4 {
+ bit 10 NARROW_TE
+ bit 9 TE_INV
+ bit 8 NOT_USE_TE
+ bit 7 DCSI_SEL
+ bit 6 MIPI_SLCD
+ bit 4 FAST_MODE
+ bit 3 GATE_MASK
+ bit 2 DMA_MODE
+ bit 1 DMA_START
+ bit 0 DMA_TX_EN
+ }
+
+ reg MSTATE 0xa8 {
+ fld 31 16 LCD_ID
+ bit 0 BUSY
+ }
+
+ reg MDATA 0xac {
+ fld 31 30 TYPE { enum CMD 1; enum DAT 0 }
+ fld 23 0 DATA
+ }
+
+ reg WTIME 0xb0 {
+ fld 31 24 DHTIME
+ fld 23 16 DLTIME
+ fld 15 8 CHTIME
+ fld 7 0 CLTIME
+ }
+
+ reg TASH 0xb4 {
+ fld 15 8 TAH
+ fld 7 0 TAS
+ }
+
+ reg SMWT 0xbc
+}
+
+node DDRC {
+ title "DDR controller AHB2 group"
+ desc "note: incomplete, only lists registers used by DDR init code"
+ addr 0xb34f0000
+
+ reg STATUS 0x00
+ reg CFG 0x04
+ reg CTRL 0x08
+ reg TIMING1 0x60
+ reg TIMING2 0x64
+ reg TIMING3 0x68
+ reg TIMING4 0x6c
+ reg TIMING5 0x70
+ reg TIMING6 0x74
+ reg REFCNT 0x18
+ reg MMAP0 0x24
+ reg MMAP1 0x28
+ reg DLP 0xbc
+ reg REMAP1 0x9c
+ reg REMAP2 0xa0
+ reg REMAP3 0xa4
+ reg REMAP4 0xa8
+ reg REMAP5 0xac
+ reg AUTOSR_CNT 0x308
+ reg AUTOSR_EN 0x304
+}
+
+node DDRC_APB {
+ title "DDR controller APB group"
+ desc "note: incomplete, only lists registers used by DDR init code"
+ addr 0xb3012000
+
+ reg CLKSTP_CFG 0x68
+ reg PHYRST_CFG 0x80
+}
+
+node DDRPHY {
+ title "DDR PHY group"
+ desc "note: incomplete, only lists registers used by DDR init code"
+ addr 0xb3011000
+
+ reg PIR 0x04
+ reg PGCR 0x08
+ reg PGSR 0x0c
+ reg DLLGCR 0x10
+ reg ACDLLCR 0x14
+ reg PTR0 0x18
+ reg PTR1 0x1c
+ reg PTR2 0x20
+ reg ACIOCR 0x24
+ reg DXCCR 0x28
+ reg DSGCR 0x2c
+ reg DCR 0x30
+ reg DTPR0 0x34
+ reg DTPR1 0x38
+ reg DTPR2 0x3c
+ reg MR0 0x40
+ reg MR1 0x44
+ reg MR2 0x48
+ reg MR3 0x4c
+ reg DTAR 0x54
+ reg DXGCR { instance 0x1c0 0x40 4 }
+}
+
+node CPM {
+ title "Clock, Reset and Power Manager"
+ addr 0xb0000000
+
+ reg CCR 0x00 {
+ fld 31 30 SEL_SRC { enum STOP 0; enum EXCLK 1; enum APLL 2; }
+ fld 29 28 SEL_CPLL { enum STOP 0; enum SCLK_A 1; enum MPLL 2; }
+ fld 27 26 SEL_H0PLL { enum STOP 0; enum SCLK_A 1; enum MPLL 2; }
+ fld 25 24 SEL_H2PLL { enum STOP 0; enum SCLK_A 1; enum MPLL 2; }
+ bit 23 GATE_SCLKA
+ bit 22 CE_CPU
+ bit 21 CE_AHB0
+ bit 20 CE_AHB2
+ fld 19 16 PDIV
+ fld 15 12 H2DIV
+ fld 11 8 H0DIV
+ fld 7 4 L2DIV
+ fld 3 0 CDIV
+ }
+
+ reg CSR 0xd4 {
+ bit 31 SRC_MUX
+ bit 30 CPU_MUX
+ bit 29 AHB0_MUX
+ bit 28 AHB2_MUX
+ bit 27 DDR_MUX
+ bit 2 H2DIV_BUSY
+ bit 1 H0DIV_BUSY
+ bit 0 CDIV_BUSY
+ }
+
+ reg DDRCDR 0x2c {
+ fld 31 30 CLKSRC { enum STOP 0; enum SCLK_A 1; enum MPLL 2; }
+ bit 29 CE
+ bit 28 BUSY
+ bit 27 STOP
+ bit 26 GATE_EN
+ bit 25 CHANGE_EN
+ bit 24 FLAG
+ fld 3 0 CLKDIV
+ }
+
+ reg LPCDR 0x64 {
+ bit 31 CLKSRC { enum SCLK_A 0; enum MPLL 1; }
+ bit 28 CE
+ bit 27 BUSY
+ bit 26 STOP
+ fld 7 0 CLKDIV
+ }
+
+ reg MSC0CDR 0x68 {
+ bit 31 CLKSRC { enum SCLK_A 0; enum MPLL 1; }
+ bit 29 CE
+ bit 28 BUSY
+ bit 27 STOP
+ bit 15 S_CLK0_SEL { enum 90DEG 0; enum 180DEG 1; }
+ fld 7 0 CLKDIV
+ }
+
+ reg MSC1CDR 0xa4 {
+ bit 29 CE
+ bit 28 BUSY
+ bit 27 STOP
+ bit 15 S_CLK1_SEL { enum 90DEG 0; enum 180DEG 1; }
+ fld 7 0 CLKDIV
+ }
+
+ reg DRCG 0xd0
+
+ reg APCR 0x10 {
+ bit 31 BS
+ fld 30 24 PLLM
+ fld 22 18 PLLN
+ fld 17 16 PLLOD
+ bit 15 LOCK
+ bit 10 ON
+ bit 9 BYPASS
+ bit 8 ENABLE
+ fld 7 0 PLLST
+ }
+
+ reg MPCR 0x14 {
+ bit 31 BS
+ fld 30 24 PLLM
+ fld 22 18 PLLN
+ fld 17 16 PLLOD
+ bit 7 ENABLE
+ bit 6 BYPASS
+ bit 1 LOCK
+ bit 0 ON
+ }
+
+ reg LCR 0x04 {
+ fld 19 8 PST
+ fld 1 0 LPM { enum IDLE 0; enum SLEEP 1 }
+ }
+
+ reg PSWC0ST 0x90
+ reg PSWC1ST 0x94
+ reg PSWC2ST 0x98
+ reg PSWC3ST 0x9c
+
+ reg CLKGR 0x20 {
+ desc "Clock gate register"
+ bit 31 DDR
+ bit 30 CPU_BIT # can't be called CPU because Rockbox #defines that
+ bit 29 AHB0
+ bit 28 APB0
+ bit 27 RTC
+ bit 26 PCM
+ bit 25 MAC
+ bit 24 AES
+ bit 23 LCD
+ bit 22 CIM
+ bit 21 PDMA
+ bit 20 OST
+ bit 19 SSI
+ bit 18 TCU
+ bit 17 DMIC
+ bit 16 UART2
+ bit 15 UART1
+ bit 14 UART0
+ bit 12 JPEG
+ bit 11 AIC
+ bit 9 I2C2
+ bit 8 I2C1
+ bit 7 I2C0
+ bit 6 SCC
+ bit 5 MSC1
+ bit 4 MSC0
+ bit 3 OTG
+ bit 2 SFC
+ bit 1 EFUSE
+ }
+}
+
+node TCU {
+ title "Timer/counter unit"
+ addr 0xb0002000
+
+ reg STATUS 0xf0 { variant set 4; variant clr 8 }
+ reg STOP 0x1c { variant set 0x10; variant clr 0x20 }
+ reg ENABLE 0x10 { variant set 4; variant clr 8 }
+ reg FLAG 0x20 { variant set 4; variant clr 8 }
+ reg MASK 0x30 { variant set 4; variant clr 8 }
+ reg CMP_FULL {
+ desc "called Data FULL by Ingenic"
+ instance 0x40 0x10 8
+ }
+ reg CMP_HALF {
+ desc "called Data HALF by Ingenic"
+ instance 0x44 0x10 8
+ }
+ reg COUNT {
+ instance 0x48 0x10 8
+ }
+ reg CTRL {
+ instance 0x4c 0x10 8
+ bit 11 BYPASS
+ bit 10 CLRZ
+ bit 9 SHUTDOWN { enum GRACEFUL 0; enum ABRUPT 1; }
+ bit 8 INIT_LVL
+ bit 7 PWM_EN
+ bit 6 PWM_IN_EN
+ fld 5 3 PRESCALE { enum BY_1 0; enum BY_4 1; enum BY_16 2;
+ enum BY_64 3; enum BY_256 4; enum BY_1024 5; }
+ fld 2 0 SOURCE { enum EXT 4; enum RTC 2; enum PCLK 1; }
+ }
+}
+
+node OST {
+ title "Operating system timer"
+ addr 0xb2000000
+
+ reg CTRL 0x00 {
+ field 5 3 PRESCALE2 { enum BY_1 0; enum BY_4 1; enum BY_16 2; }
+ field 2 0 PRESCALE1 { enum BY_1 0; enum BY_4 1; enum BY_16 2; }
+ }
+
+ reg ENABLE 0x04 {
+ variant set 0x30
+ variant clr 0x34
+ bit 0 OST1
+ bit 1 OST2
+ }
+
+ reg CLEAR 0x08 {
+ bit 0 OST1
+ bit 1 OST2
+ }
+
+ reg 1FLG 0x0c
+ reg 1MSK 0x10
+ reg 1DFR 0x14
+ reg 1CNT 0x18
+
+ reg 2CNTH 0x1c
+ reg 2CNTL 0x20
+ reg 2CNTHB 0x24
+}
+
+node INTC {
+ title "Interrupt controller"
+ # Documented address in Ingenic's manual is a typo (= GPIO base address).
+ # This is the correct address from their Linux source.
+ addr 0xb0001000
+
+ reg SRC { instance 0x00 0x20 2 }
+ reg MSK { instance 0x04 0x20 2; variant set 4; variant clr 8 }
+ reg PND { instance 0x10 0x20 2 }
+}
+
+node WDT {
+ title "Watchdog timer"
+ addr 0xb0002000
+
+ reg DATA 0x00
+ reg ENABLE 0x04
+ reg COUNT 0x08
+
+ reg CTRL 0x0c {
+ field 5 3 PRESCALE { enum BY_1 0; enum BY_4 1; enum BY_16 2;
+ enum BY_64 3; enum BY_256 4; enum BY_1024 5; }
+ field 2 0 SOURCE { enum EXT 4; enum RTC 2; enum PLCK 1; }
+ }
+}
+
+node RTC {
+ title "Realtime clock"
+ addr 0xb0003000
+
+ reg CR 0x00
+ reg SR 0x04
+ reg SAR 0x08
+ reg GR 0x0c
+ reg HCR 0x20
+ reg WFCR 0x24
+ reg RCR 0x28
+ reg WCR 0x2c
+ reg RSR 0x30
+ reg SPR 0x34
+ reg WENR 0x3c
+ reg WKUPPINCR 0x48
+}
+
+node GPIO {
+ title "General purpose I/O"
+ addr 0xb0010000
+
+ # Note: only instances 0-3 and 7 are instantiated in hardware
+ reg PIN { instance 0x00 0x100 8 }
+ reg INT { instance 0x10 0x100 8; variant set 4; variant clr 8 }
+ reg MSK { instance 0x20 0x100 8; variant set 4; variant clr 8 }
+ reg PAT1 { instance 0x30 0x100 8; variant set 4; variant clr 8 }
+ reg PAT0 { instance 0x40 0x100 8; variant set 4; variant clr 8 }
+ reg FLAG { instance 0x50 0x100 8; variant clr 8 }
+ reg PULL { instance 0x70 0x100 8; variant set 4; variant clr 8 }
+
+ node C_GLITCH {
+ desc "GPIO port C: glitch filter registers"
+ addr 0x200
+ reg CFG0 0x800 { variant set 4; variant clr 8 }
+ reg CFG1 0x810 { variant set 4; variant clr 8 }
+ reg CFG2 0x820 { variant set 4; variant clr 8 }
+ reg CFG3 0x830 { variant set 4; variant clr 8 }
+ }
+
+ reg Z_GID2LD {
+ desc "GPIO port Z: atomic load register"
+ addr 0x7f0
+ }
+}
+
+node I2C {
+ title "I2C bus controller"
+ instance 0xb0050000 0x1000 3
+
+ reg CON 0x00 {
+ bit 6 SLVDIS
+ bit 5 RESTART
+ bit 4 MATP
+ bit 3 SATP
+ fld 2 1 SPEED { enum 100K 1; enum 400K 2; }
+ bit 0 MD
+ }
+
+ reg DC 0x10 {
+ bit 10 RESTART
+ bit 9 STOP
+ bit 8 CMD
+ fld 7 0 DAT
+ }
+
+ reg INTST 0x2c {
+ bit 11 GC
+ bit 10 STT
+ bit 9 STP
+ bit 8 ACT
+ bit 7 RXDN
+ bit 6 TXABT
+ bit 5 RDREQ
+ bit 4 TXEMP
+ bit 3 TXOF
+ bit 2 RXFL
+ bit 1 RXOF
+ bit 0 RXUF
+ }
+
+ reg INTMSK 0x30 {
+ bit 11 GC
+ bit 10 STT
+ bit 9 STP
+ bit 8 ACT
+ bit 7 RXDN
+ bit 6 TXABT
+ bit 5 RDREQ
+ bit 4 TXEMP
+ bit 3 TXOF
+ bit 2 RXFL
+ bit 1 RXOF
+ bit 0 RXUF
+ }
+
+ reg RINTST 0x34 {
+ bit 11 GC
+ bit 10 STT
+ bit 9 STP
+ bit 8 ACT
+ bit 7 RXDN
+ bit 6 TXABT
+ bit 5 RDREQ
+ bit 4 TXEMP
+ bit 3 TXOF
+ bit 2 RXFL
+ bit 1 RXOF
+ bit 0 RXUF
+ }
+
+ reg ENABLE 0x6c {
+ bit 1 ABORT
+ bit 0 ACTIVE
+ }
+
+ reg STATUS 0x70 {
+ bit 6 SLVACT
+ bit 5 MSTACT
+ bit 4 RFF
+ bit 3 RFNE
+ bit 2 TFE
+ bit 1 TFNF
+ bit 0 ACT
+ }
+
+ reg ENBST 0x9c {
+ bit 2 SLVRDLST
+ bit 1 SLVDISB
+ bit 0 ACTIVE
+ }
+
+ reg TAR 0x04
+ reg SAR 0x08
+ reg SHCNT 0x14
+ reg SLCNT 0x18
+ reg FHCNT 0x1c
+ reg FLCNT 0x20
+ reg RXTL 0x38
+ reg TXTL 0x3c
+ reg TXFLR 0x74
+ reg RXFLR 0x78
+ reg SDAHD 0x7c
+ reg ABTSRC 0x80
+ reg DMACR 0x88
+ reg DMATDLR 0x8c
+ reg DMARDLR 0x90
+ reg SDASU 0x94
+ reg ACKGC 0x98
+ reg FLT 0xa0
+
+ reg CINT 0x40
+ reg CRXUF 0x44
+ reg CRXOF 0x48
+ reg CTXOF 0x4c
+ reg CRXREQ 0x50
+ reg CTXABT 0x54
+ reg CRXDN 0x58
+ reg CACT 0x5c
+ reg CSTP 0x60
+ reg CSTT 0x64
+ reg CGC 0x68
+}
+
+node MSC {
+ title "MMC/SD/CE-ATA controller"
+ instance 0xb3450000 0x10000 2
+
+ reg CTRL 0x00 {
+ bit 15 SEND_CCSD
+ bit 14 SEND_AS_CCSD
+ bit 7 EXIT_MULTIPLE
+ bit 6 EXIT_TRANSFER
+ bit 5 START_READ_WAIT
+ bit 4 STOP_READ_WAIT
+ bit 3 RESET
+ bit 2 START_OP
+ fld 1 0 CLOCK { enum DO_NOTHING 0; enum STOP 1; enum START 2; }
+ }
+
+ reg STAT 0x04 {
+ bit 31 AUTO_CMD12_DONE
+ fld 28 24 PINS
+ bit 20 BCE
+ bit 19 BDE
+ bit 18 BAE
+ bit 17 BAR
+ bit 16 DMAEND
+ bit 15 IS_RESETTING
+ bit 14 SDIO_INT_ACTIVE
+ bit 13 PROG_DONE
+ bit 12 DATA_TRAN_DONE
+ bit 11 END_CMD_RES
+ bit 10 DATA_FIFO_AFULL
+ bit 9 IS_READ_WAIT
+ bit 8 CLOCK_EN
+ bit 7 DATA_FIFO_FULL
+ bit 6 DATA_FIFO_EMPTY
+ bit 5 CRC_RES_ERROR
+ bit 4 CRC_READ_ERROR
+ fld 3 2 CRC_WRITE_ERROR { enum NONE 0; enum BADDATA 1; enum NOCRC 2 }
+ bit 1 TIME_OUT_RES
+ bit 0 TIME_OUT_READ
+ }
+
+ reg CMDAT 0x0c {
+ bit 31 CCS_EXPECTED
+ bit 30 READ_CEATA
+ bit 27 DIS_BOOT
+ bit 25 EXP_BOOT_ACK
+ bit 24 BOOT_MODE
+ bit 17 SDIO_PRDT
+ bit 16 AUTO_CMD12
+ fld 15 14 RTRG { enum GE16 0; enum GE32 1; enum GE64 2; enum GE96 3 }
+ fld 13 12 TTRG { enum LE16 0; enum LE32 1; enum LE64 2; enum LE96 3 }
+ bit 11 IO_ABORT
+ fld 10 9 BUS_WIDTH { enum 1BIT 0; enum 4BIT 2; enum 8BIT 3; }
+ bit 7 INIT
+ bit 6 BUSY
+ bit 5 STREAM_BLOCK
+ bit 4 WRITE_READ
+ bit 3 DATA_EN
+ fld 2 0 RESP_FMT
+ }
+
+ reg IMASK 0x24 {
+ bit 31 DMA_DATA_DONE
+ fld 28 24 PINS
+ bit 23 WR_ALL_DONE
+ bit 20 BCE
+ bit 19 BDE
+ bit 18 BAE
+ bit 17 BAR
+ bit 16 DMAEND
+ bit 15 AUTO_CMD12_DONE
+ bit 14 DATA_FIFO_FULL
+ bit 13 DATA_FIFO_EMPTY
+ bit 12 CRC_RES_ERROR
+ bit 11 CRC_READ_ERROR
+ bit 10 CRC_WRITE_ERROR
+ bit 9 TIME_OUT_RES
+ bit 8 TIME_OUT_READ
+ bit 7 SDIO
+ bit 6 TXFIFO_WR_REQ
+ bit 5 RXFIFO_RD_REQ
+ bit 2 END_CMD_RES
+ bit 1 PROG_DONE
+ bit 0 DATA_TRAN_DONE
+ }
+
+ reg IFLAG 0x28 {
+ bit 31 DMA_DATA_DONE
+ fld 28 24 PINS
+ bit 23 WR_ALL_DONE
+ bit 20 BCE
+ bit 19 BDE
+ bit 18 BAE
+ bit 17 BAR
+ bit 16 DMAEND
+ bit 15 AUTO_CMD12_DONE
+ bit 14 DATA_FIFO_FULL
+ bit 13 DATA_FIFO_EMPTY
+ bit 12 CRC_RES_ERROR
+ bit 11 CRC_READ_ERROR
+ bit 10 CRC_WRITE_ERROR
+ bit 9 TIME_OUT_RES
+ bit 8 TIME_OUT_READ
+ bit 7 SDIO
+ bit 6 TXFIFO_WR_REQ
+ bit 5 RXFIFO_RD_REQ
+ bit 2 END_CMD_RES
+ bit 1 PROG_DONE
+ bit 0 DATA_TRAN_DONE
+ }
+
+ reg LPM 0x40 {
+ fld 31 30 DRV_SEL {
+ enum FALL_EDGE 0
+ enum RISE_EDGE_DELAY_1NS 1
+ enum RISE_EDGE_DELAY_QTR_PHASE 2
+ }
+
+ fld 29 28 SMP_SEL {
+ enum RISE_EDGE 0
+ enum RISE_EDGE_DELAYED 1
+ }
+
+ bit 0 ENABLE
+ }
+
+ reg DMAC 0x44 {
+ bit 7 MODE_SEL
+ fld 6 5 ADDR_OFFSET
+ bit 4 ALIGN_EN
+ fld 3 2 INCR
+ bit 1 DMASEL
+ bit 0 ENABLE
+ }
+
+ reg CTRL2 0x58 {
+ fld 28 24 PIN_INT_POLARITY
+ bit 4 STPRM
+ fld 2 0 SPEED {
+ enum DEFAULT 0
+ enum HIGHSPEED 1
+ enum SDR12 2
+ enum SDR25 3
+ enum SDR50 4
+ }
+ }
+
+ reg CLKRT 0x08
+ reg RESTO 0x10
+ reg RDTO 0x14
+ reg BLKLEN 0x18
+ reg NOB 0x1c
+ reg SNOB 0x20
+ reg CMD 0x2c
+ reg ARG 0x30
+ reg RES 0x34
+ reg RXFIFO 0x38
+ reg TXFIFO 0x3c
+ reg DMANDA 0x48
+ reg DMADA 0x4c
+ reg DMALEN 0x50
+ reg DMACMD 0x54
+ reg RTCNT 0x5c
+}