diff options
author | Aidan MacDonald <amachronic@protonmail.com> | 2021-02-27 22:05:11 +0000 |
---|---|---|
committer | Aidan MacDonald <amachronic@protonmail.com> | 2021-03-02 00:36:01 +0000 |
commit | 73cee8f17702d0fdc3e0508e8cf7193faae5f015 (patch) | |
tree | d83cb08541a2f78f1e7512de7abd0ce788eb8eb5 | |
parent | 7418ec5009a0203b562bcf128713ef741815fe0e (diff) | |
download | rockbox-73cee8f177.tar.gz rockbox-73cee8f177.zip |
Add RegGen-NG tool and definitions for Ingenic X1000
Change-Id: Ib9ec35c068e1cff8dcf120a13cfe3f5f58908a95
-rwxr-xr-x | utils/reggen-ng/reggen-ng.py | 465 | ||||
-rw-r--r-- | utils/reggen-ng/x1000.reggen | 742 |
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 +} |