MMCHS and I2C code imported into main tree right now as a kernel-space library.
authorSimon Gerber <simon.gerber@inf.ethz.ch>
Mon, 8 Jul 2013 09:30:04 +0000 (11:30 +0200)
committerGerd Zellweger <mail@gerdzellweger.com>
Tue, 16 Jul 2013 12:55:00 +0000 (14:55 +0200)
Needs to be changed to a user space driver.

21 files changed:
devices/Hakefile
devices/omap/omap44xx_cm2.dev [new file with mode: 0644]
devices/omap/omap44xx_ctrlmod.dev [new file with mode: 0644]
devices/omap/omap44xx_mmchs.dev [new file with mode: 0644]
devices/omap/omap44xx_mmchs1.dev
devices/sdhc.dev [new file with mode: 0644]
devices/ti_i2c.dev [new file with mode: 0644]
devices/ti_twl6030.dev [new file with mode: 0644]
errors/errno.fugu
kernel/Hakefile
kernel/arch/armv7/gic.c
kernel/include/arch/armv7/gic.h [new file with mode: 0644]
kernel/include/arch/armv7/ti_i2c.h [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/Hakefile [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/cm2.c [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/ctrlmod.c [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/i2c.c [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/mmchs.c [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/omap44xx_cm2.h [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/omap44xx_ctrlmod.h [new file with mode: 0644]
usr/drivers/omap44xx/mmchs/omap44xx_mmchs.h [new file with mode: 0644]

index 9198e32..c183f6b 100644 (file)
            "sp804_pit",
            "cortex_a9_pit",
            "a9scu",
-          "omap/omap_uart",
-          "omap/omap44xx_emif",
-          "omap/omap44xx_gpio",
-          "omap/omap44xx_id",
-          "omap/omap44xx_usbconf",
+           "ti_i2c",
+           "ti_twl6030",
+           "sdhc",
+           "omap/omap_uart",
+           "omap/omap44xx_emif",
+           "omap/omap44xx_gpio",
+           "omap/omap44xx_id",
+           "omap/omap44xx_usbconf",
           "omap/omap44xx_mmu",
+           "omap/omap44xx_ctrlmod",
            "omap/omap44xx_cam_prm",
            "omap/omap44xx_cam_cm2",
            "omap/omap44xx_fdif",
            "omap/omap44xx_sr_mpu",
-           "omap/omap44xx_device_prm"
+           "omap/omap44xx_device_prm",
+           "omap/omap44xx_mmchs",
+           "omap/omap44xx_cm2"
          ], arch <- allArchitectures
 ] ++
 
diff --git a/devices/omap/omap44xx_cm2.dev b/devices/omap/omap44xx_cm2.dev
new file mode 100644 (file)
index 0000000..20b110a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * omap44xx_cm2.dev
+ *
+ * DESCRIPTION: Power Management Framework (PandaBoard)
+ *
+ * See:
+ * OMAP4430 Multimedia Device Silicon Revision 2.x Technical Reference Manual (Rev. 0)
+ * Chapter: 3.6.3.2.4 and 3.11.29 - 3.11.40
+ * Registers: Table 3-1286 on page 918
+ *
+ */
+device omap44xx_cm2 msbfirst (addr cm2_base, addr cm2_clkgen_base, addr l4per_base) "TI CM2 Clock Generator" {
+
+    /*
+     * Ignoring the remaining bits, since we don't use them .. 
+     * see table 3-1287, page 918                                   
+     * XXX need to add output for L{3,4}_ICLK to see if it is turned on
+     */
+    register CM_L3INIT_CLKSTCTRL addr(cm2_base, 0x0) "Enable power state transitions" {
+        _                             14;
+        CLKACTIVITY_INIT_HSMMC1_FCLK   1    ro     "State of functional clock for MMC1";
+        _                             15;
+        CLKTRCTRL                      2    rw     "Clock state transition of L3INIT clock domain";
+    };
+
+    register CM_L3INIT_HSMMC1_CLKCTRL addr(cm2_base, 0x28) "management of MMC1 clocks" {
+        _                              7;
+        CLKSEL                         1    rw    "Source of functional clock";
+        _                              5;
+        STBYST                         1    ro    "Standby status";
+        IDLEST                         2    ro    "Idel status";
+        _                             14;
+        MODULEMODE                     2    rw    "Clock management mode";
+    };
+
+    register CM_DIV_M4_DPLL_PER addr(cm2_clkgen_base, 0x58) "Control over CLKOUT1 of HSDIVIDER" {
+        _                             19;
+        HSDIVIDER_CLKOUT1_PWDN         1    rw    "Power control for M4 divider";
+        _                              2;
+        ST_HSDIVIDER_CLKOUT1           1    ro    "Status of HSDIVIDER CLKOUT1";
+        HSDIVIDER_CLKOUT1_GATE_CTRL    1    rw    "Control gating of HSDIVIDER CLKOUT1";
+        _                              2;
+        HSDIVIDER_CLKOUT1_DIVCHACK     1    ro    "Toggle on this status bit after changing CLKOUT1_DIV";
+        HSDIVIDER_CLKOUT1_DIV          5    rw    "DPLL M4 post-divider factor";
+    };
+
+    constants idlest "Idle Status" {
+        idlest_functional = 0b00 "Module is fully functional";
+        idlest_transition = 0b01 "Module is performing transition";
+        idlest_idle       = 0b10 "Module is in idle mode. It's functional when using separate FCLK.";
+        idlest_disabled   = 0b11 "Module is disabled";
+    };
+    constants modmode "Module mandatory clock control" {
+        modmode_swdisabled = 0b00 "Module is disabled by software";
+        modmode_swenabled  = 0b10 "Module is explicitly enabled"; 
+    };
+    regtype clkctrl "clock control" {
+        _ 14 rsvd;
+        idlest 2 type(idlest) "Module idle status";
+        _ 14 rsvd;
+        modulemode 2 type(modmode) "Mandatory clock control";
+    };
+    register l4per_i2c1_clkctrl addr(l4per_base, 0xa0) type(clkctrl);
+    register l4per_i2c2_clkctrl addr(l4per_base, 0xa8) type(clkctrl);
+    register l4per_i2c3_clkctrl addr(l4per_base, 0xb0) type(clkctrl);
+    register l4per_i2c4_clkctrl addr(l4per_base, 0xb8) type(clkctrl);
+};
diff --git a/devices/omap/omap44xx_ctrlmod.dev b/devices/omap/omap44xx_ctrlmod.dev
new file mode 100644 (file)
index 0000000..57c8f1d
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ */
+
+/*
+ * omap44xx_ctrlmod.dev
+ *
+ * DESCRIPTION: Control module
+ *
+ * See:
+ * OMAP4460 Multimedia Device Silicon Revision 1.x (Version Q)
+ * Chapter: 18
+ * Registers: 18.6, page 3688 
+ *
+ * XXX Need to write a register type for pad multiplexing
+ */
+ device omap44xx_ctrlmod msbfirst (addr gen_core, 
+                                   addr gen_wkup, 
+                                       addr pad_core, 
+                                   addr pad_wkup) "TI Control Module" {
+
+
+     // SYSCTRL_GENERAL_CORE registers
+     // relative to gen_core address
+     // --------------------------------------------------
+
+     register CONTROL_GEN_CORE_REVISION addr(gen_core, 0x0) 
+         "Control module instance revision identifier"
+         type(uint32);
+
+     // SYSCTRL_PADCONF_CORE registers
+     // relative to pad_core address
+     // --------------------------------------------------
+
+     // Register format for pad configuration
+     regtype pad_conf "Configuration of Pads. Two Pads per register" {
+         PAD2_WAKEUPEVENT            1    ro     "Pad_x wake-up event status latched in IO";
+         PAD2_WAKEUPENABLE           1    rw     "Input pad wake-up enable";
+         PAD2_OFFMODEPULLTYPESEL     1    rw     "OffMode mode pullup/down selection";
+         PAD2_OFFMODEPULLUDENABLE    1    rw     "OffMode mode pullup/down enable";
+         PAD2_OFFMODEOUTVALUE        1    rw     "OffMode mode output value";
+         PAD2_OFFMODEOUTENABLE       1    rw     "OffMode mode output enable value";
+         PAD2_OFFMODEENABLE          1    rw     "OffMode mode override control";
+         PAD2_INPUTENABLE            1    rw     "Input enable value";
+         _                           6 rsvd;
+         PAD2_MUXMODE                2    rw     "Functional mux selection";
+
+         PAD1_WAKEUPEVENT            1    ro     "Pad_x wake-up event status latched in IO";
+         PAD1_WAKEUPENAB             1    rw     "Input pad wake-up enable";
+         PAD1_OFFMODEPULLTYPESEL     1    rw     "OffMode mode pullup/down selection";
+         PAD1_OFFMODEPULLUDENABLE    1    rw     "OffMode mode pullup/down enable";
+         PAD1_OFFMODEOUTVALUE        1    rw     "OffMode mode output value";
+         PAD1_OFFMODEOUTENABLE       1    rw     "OffMode mode output enable value";
+         PAD1_OFFMODEENABLE          1    rw     "OffMode mode override control";
+         PAD1_INPUTENABLE            1    rw     "Input enable value";
+         _                           6 rsvd;
+         PAD1_MUXMODE                2    rw     "Functional mux selection";
+     };
+
+     register PAD_AD8 addr(pad_core, 0x50) type(pad_conf);
+     register PAD_AD10 addr(pad_core, 0x54) type(pad_conf);
+     register PAD_AD12 addr(pad_core, 0x58) type(pad_conf);
+     register PAD_AD14 addr(pad_core, 0x5c) type(pad_conf);
+     register PAD_NWP addr(pad_core, 0x7c) type(pad_conf);
+     register PAD_NAVD_ALE addr(pad_core, 0x80) type(pad_conf);
+     register PAD_USBC1 addr(pad_core, 0xe0) type(pad_conf);
+     register PAD_CMD addr(pad_core, 0xe4) type(pad_conf);
+     register PAD_DAT1 addr(pad_core, 0xe8) type(pad_conf);
+     register PAD_DAT3 addr(pad_core, 0xeC) type(pad_conf);
+     register PAD_DAT5 addr(pad_core, 0xf0) type(pad_conf);
+     register PAD_DAT7 addr(pad_core, 0xf4) type(pad_conf);
+
+     constants voltage "Voltage bit" {
+         vlt_low = 0b0 "1.8V";
+         vlt_hi  = 0b1 "3.0V";
+     };
+
+     register PBIASLITE addr(pad_core,0x600)
+         "PBIASLITE control for extended drain pad settings"
+     { 
+         _                            20 rsvd;
+         USBC1_ICUSB_PWRDNZ           1 rw "PWRDNZ for USBC1 IO";
+         MMC1_PBIASLITE_VMODE         1 rw type(voltage) "MMC1 PBIAS VMODE control";
+         MMC1_PBIASLITE_PWRDNZ        1 rw "PWRDNZ for MMC1 PBIAS";
+         MMC1_PBIASLITE_VMODE_ERROR   1 ro "Error bit for MMC1 PBIAS VMODE";
+         MMC1_PBIASLITE_SUPPLY_HI_OUT 1 ro type(voltage) "Indicator for SDMMC1_VDDS voltage";
+         MMC1_PBIASLITE_HIZ_MODE      1 rw "MMC1 PBIAS hi-z mode";
+         MMC1_PWRDNZ                  1 rw "PWRDNZ for MMC1 IO";
+         PBIASLITE1_VMODE             1 rw type(voltage) "PBIAS VMODE control";
+         PBIASLITE1_PWRDNZ            1 rw "PWRDNZ for PBIAS";
+         PBIASLITE1_VMODE_ERROR       1 ro "Error bit for PBIAS VMODE";
+         PBIASLITE1_SUPPLY_HI_OUT     1 ro type(voltage) "Indicator for PBIAS voltage";
+         PBIASLITE1_HIZ_MODE          1 rw "PBIAS hi-z mode";
+     };
+
+     constants usbc1_speeds "Clock speeds for usbc1" {
+         usbc1_spd_slow = 0b0 "FMAX = 26MHz @ 30pF";
+         usbc1_spd_fast = 0b1 "FMAX = 65MHz @ 30pF";
+     };
+
+     constants mmc1_speeds "Clock speeds for sdmmc1" {
+         mmc1_spd_slow = 0b000 "FMAX = 26MHz @ 30pF";
+         mmc1_spd_fast = 0b111 "FMAX = 65MHz @ 30pF";
+     };
+
+     constants mmc1_pustrengths "Pull up strenghts for sdmmc1" {
+         mmc1_pstr_strong = 0b0000 "Pull up with 50 to 110 kOhm";
+         mmc1_pstr_weak   = 0b1111 "Pull up with 10 to 50 kOhm";
+     };
+
+     register CONTROL_MMC1 addr(pad_core,0x628) "MMC1 control" {
+         _                      21 rsvd;
+         USBC1_ICUSB_DM_PDDIS   1 rw "ICUSB DM pull-down disable";
+         USBC1_ICUSB_DP_PDDIS   1 rw "ICUSB DP pull-down disable";
+         USB_FD_CDEN            1 rw "USB FD pull-down select";
+         USBC1_DR0_SPEEDCTRL    1 rw type(usbc1_speeds) "Speed control for USBC1";
+         /* Speedcontrol is actually 3 1-bit registers but afaict they should
+          * be set to the same value all the time -SG
+          */
+         SDMMC1_SPEEDCTRL       3 rw type(mmc1_speeds) "Speed control for SDMMC1";
+         /* Pullstrength control is actually 4 1-bit registers but afaict
+          * they should be set to the same value all the time -SG
+          */
+         SDMMC1_PUSTRENGTH      4 rw type(mmc1_pustrengths) "Pullstrength control for SDMMC1";
+     };
+ };
diff --git a/devices/omap/omap44xx_mmchs.dev b/devices/omap/omap44xx_mmchs.dev
new file mode 100644 (file)
index 0000000..a448c64
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich,
+ */
+
+/*
+ * omap44xx_mmchs.dev
+ *
+ * DESCRIPTION: MMC host controller for TI devices (PandaBoard)
+ *
+ * See:
+ * OMAP4430 Multimedia Device Silicon Revision 2.x 
+ *          Technical Reference Manual (Rev. 0)
+ * SD Card Association - Physical Layer Simplified Specification Version 3.01 
+ *          (referred to as PLS)
+ * devices/sdhc.dev: the rest of this device. 
+ * 
+ * This specification holds the OMAP44xx-specific part of the device;
+ * the rest (from offset 0x200 up) is mostly a standard SDHC adaptor,
+ * for which see the separate file sdhc.dev.   The main exception is
+ * the additional use of the sdhc arg1 register at 0x208 covered in
+ * this file. 
+ *
+ */
+ device omap44xx_mmchs msbfirst (addr base) "TI MMC host controller" {
+        
+     register HL_REV ro addr(base, 0x0) "revision identifier" 
+         type(uint32);
+     
+     register HL_HWINFO ro addr(base, 0x4) "hardware configuration" {
+         _              25 mbz;
+         RETMODE        1       "Retention Mode";
+         MEM_SIZE       4       "FIFO buffer size";
+         MERGE_MEM      1       "merged FIFO buffer";
+         MADMA_EN       1       "DMA master enabled";
+     };
+
+     // table 24-56, page 5144
+     register HL_SYSCONFIG rw addr(base, 0x10) "Clock management config" {
+         _              26 mbz;
+         STANDBYMODE    2       "Local initiator state mgmt mode conf";
+         IDLEMODE       2       "Local target state mgmt mode conf";
+         FREEEMU        1       "Sensitivity to emulation input signal";
+         SOFTRESET      1       "Software reset (optional)";
+     };
+
+     // table 24-66, page 5145
+     register SYSCONFIG rw addr(base, 0x110) "System config" {
+         _              18 mbz;
+         STANDBYMODE    2       "Master interface power management";
+         _              2 mbz;
+         CLOCKACTIVITY  2       "Clock activity during wake up period";
+         _              3 mbz;
+         SIDLEMODE      2       "Power management";
+         ENAWAKEUP      1       "Wakeup feature control";
+         SOFTRESET      1       "Software reset";
+         AUTOIDLE       1       "Internal Clock gating strategy";
+     };
+
+     // table 24-68, page 5147
+     register SYSSTATUS ro addr(base, 0x114) "Status information" {
+         _              31 mbz;
+         RESETDONE      1       "Internal reset monitoring";
+     };
+
+
+     // table 24-71
+     register CSRE rw addr(base, 0x124) "Card status response error"
+         type(uint32);
+     
+     // table 24-73
+     register SYSTEST addr(base, 0x128) "System test" {
+         _              15 mbz;
+         OBI            1 rw    "Out-Of-Band Interrupt (OBI)";
+         SDCD           1 ro    "Card detect input signal (SDCD)";
+         SDWP           1 ro    "Write protect input signal (SDWP)";
+         WAKD           1 rw    "Wake request output signal";
+         SSB            1 rw    "Set status bit";
+         D7D            1 rw    "DAT7 i/o signal";
+         D6D            1 rw    "DAT6 i/o signal";
+         D5D            1 rw    "DAT5 i/o signal";
+         D4D            1 rw    "DAT4 i/o signal";
+         D3D            1 rw    "DAT3 i/o signal";
+         D2D            1 rw    "DAT2 i/o signal";
+         D1D            1 rw    "DAT1 i/o signal";
+         D0D            1 rw    "DAT0 i/o signal";
+         DDIR           1 rw    "DAT[7:0] pins direction";
+         CDAT           1 rw    "CMD input/output signal";
+         CDIR           1 rw    "CMD pin direction";
+         MCKD           1 rw    "Clock output signal";
+     };
+
+     // table 24-74, page 5152
+     register CON rw addr(base, 0x12c) "Configuration" {
+         _              10 mbz;
+         SDMA_LNE       1       "Slave DMA/Edge Request";
+         DMA_MNS        1       "DMA Master or Slave selection";
+         DDR            1       "Dual Data Rate mode";
+         BOOT_CF0       1       "Boot status supported";
+         BOOT_ACK       1       "Book acknowledge received";
+         CLKEXTFREE     1       "External clock free running";
+         PADEN          1       "Control Power for MMC Lines";
+         OBIE           1       "Out-of-Band Interrupt Enable";
+         OBIP           1       "Out-of-Band Interrupt Polarity";
+         CEATA          1       "CE-ATA control mode";
+         CTPL           1       "Control power for DAT[1] line";
+         DVAL           2       "Debounce filter value";
+         WPP            1       "Write protect polarity";
+         CDP            1       "Card detect polarity";
+         MIT            1       "MMC interrupt command";
+         DW8            1       "8-bit mode MMC select";
+         MODE           1       "Mode select";
+         STR            1       "Stream command";
+         HR             1       "Broadcast host response";
+         INIT           1       "Send init stream";
+         OD             1       "Card open drain mode";
+     };
+
+     // table 24-77
+     register PWRCNT rw addr(base, 0x130) "Power control" {
+         _              16 mbz;
+         VAL            16      "Power counter value";
+     };
+   
+ };
index e0dc81f..4b0bf07 100644 (file)
@@ -80,10 +80,8 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants softreset_status width(1) "" {
-        SOFTRESET_0_w = 0 "No action";
         SOFTRESET_0_r = 0 "Reset done, no pending action";
         SOFTRESET_1_r = 1 "Reset (software or other) ongoing";
-        SOFTRESET_1_w = 1 "Initiate software reset";
     };
     
     register mmchs_hl_sysconfig addr(base, 0x10) "Clock management configuration" {
@@ -122,8 +120,6 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
 
     constants softreset_status1 width(1) "" {
         SOFTRESET_0_r_1 = 0 "Normal mode";
-        SOFTRESET_0_w_1 = 0 "No effect.";
-        SOFTRESET_1_w_1 = 1 "Trigger a module reset.";
         SOFTRESET_1_r_1 = 1 "The module is reset.";
     };
 
@@ -170,100 +166,72 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
 
     constants wakd_status width(1) "" {
         WAKD_0_w = 0 "The pin SWAKEUP is driven low.";
-        WAKD_0_r = 0 "No action. Returns 0.";
         WAKD_1_w = 1 "The pin SWAKEUP is driven high.";
-        WAKD_1_r = 1 "No action. Returns 1.";
     };
 
     constants ssb_status width(1) "" {
         SSB_0_w = 0 "Clear this SSB bit field. Writing 0 does not clear already set status bits;";
-        SSB_0_r = 0 "No action. Returns 0.";
-        SSB_1_r = 1 "No action. Returns 1.";
         SSB_1_w = 1 "Force to 1 all status bits of the interrupt status register () only if the corresponding bit field in the Interrupt signal enable register () is set.";
     };
 
     constants d7d_status width(1) "" {
         D7D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT7 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D7D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT7 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D7D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT7 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
-        D7D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT7 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
     };
 
     constants d6d_status width(1) "" {
         D6D_0_r = 0 "If SYSTEST[DDIR] = 1 (input mode direction), returns the value on the DAT6 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D6D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT6 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D6D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT6 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
-        D6D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT6 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
     };
 
     constants d5d_status width(1) "" {
         D5D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT5 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D5D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT5 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D5D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT5 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
-        D5D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT5 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
     };
 
     constants d4d_status width(1) "" {
-        D4D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT4 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D4D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT4 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D4D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT4 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
         D4D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT4 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
     };
 
     constants d3d_status width(1) "" {
-        D3D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT3 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D3D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT3 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
         D3D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT3 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
-        D3D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT3 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
     };
 
     constants d2d_status width(1) "" {
-        D2D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT2 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D2D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT2 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D2D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT2 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
         D2D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT2 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
     };
 
     constants d1d_status width(1) "" {
         D1D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT1 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D1D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT1 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D1D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT1 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
-        D1D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT1 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
     };
 
     constants d0d_status width(1) "" {
-        D0D_0_w = 0 "If[3] DDIR = 0 (output mode direction), the DAT0 line is driven low. If [3] DDIR = 1 (input mode direction), no effect.";
         D0D_0_r = 0 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT0 line (low). If [3] DDIR = 0 (output mode direction), returns 0";
-        D0D_1_w = 1 "If[3] DDIR = 0 (output mode direction), the DAT0 line is driven high. If [3] DDIR = 1 (input mode direction), no effect.";
         D0D_1_r = 1 "If[3] DDIR = 1 (input mode direction), returns the value on the DAT0 line (high) If [3] DDIR = 0 (output mode direction), returns 1";
     };
 
     constants ddir_status width(1) "" {
         DDIR_0_w = 0 "The DAT lines are outputs (host to card)";
-        DDIR_0_r = 0 "No action. Returns 0.";
-        DDIR_1_r = 1 "No action. Returns 1.";
         DDIR_1_w = 1 "The DAT lines are inputs (card to host)";
     };
 
     constants cdat_status width(1) "" {
-        CDAT_0_w = 0 "If[1] CDIR = 0 (output mode direction), the CMD line is driven low. If [1] CDIR = 1 (input mode direction), no effect.";
         CDAT_0_r = 0 "If[1] CDIR = 1 (input mode direction), returns the value on the CMD line (low). If [1] CDIR = 0 (output mode direction), returns 0";
-        CDAT_1_w = 1 "If[1] CDIR = 0 (output mode direction), the CMD line is driven high. If [1] CDIR = 1 (input mode direction), no effect.";
         CDAT_1_r = 1 "If[1] CDIR = 1 (input mode direction), returns the value on the CMD line (high) If [1] CDIR = 0 (output mode direction), returns 1";
     };
 
     constants cdir_status width(1) "" {
-        CDIR_0_r = 0 "No action. Returns 0.";
         CDIR_0_w = 0 "The CMD line is an output (host to card)";
-        CDIR_1_r = 1 "No action. Returns 1.";
         CDIR_1_w = 1 "The CMD line is an input (card to host)";
     };
 
     constants mckd_status width(1) "" {
-        MCKD_0_r = 0 "No action. Returns 0.";
         MCKD_0_w = 0 "The output clock is driven low.";
         MCKD_1_w = 1 "The output clock is driven high.";
-        MCKD_1_r = 1 "No action. Returns 1.";
     };
     
     register mmchs_systest addr(base, 0x128) "System Test register This register is used to control the signals that connect to I/O pins when the module is configured in system test (SYSTEST) mode for boundary connectivity verification. Note: In SYSTEST mode, a write into register will not start a transfer. The buffer behaves as a stack accessible only by the local host (push and pop operations). In this mode, the Transfer Block Size ([11:0] BLEN) and the Blocks count for current transfer ([31:16] NBLK) are needed to generate a Buffer write ready interrupt ([4] BWR) or a Buffer read ready interrupt ([5] BRR) and DMA requests if enabled." {
@@ -303,10 +271,8 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants boot_cf0_status width(1) "" {
-        BOOT_CF0_0_w = 0 "CMD line is released when it was previously forced to 0 by a boot sequence.";
         BOOT_CF0_0_r = 0 "CMD line not forced";
         BOOT_CF0_1_r = 1 "CMD line forced to 0 is enabled";
-        BOOT_CF0_1_w = 1 "CMD line forced to 0 is enabled and will be active after writing into";
     };
 
     constants boot_ack_status width(1) "" {
@@ -820,80 +786,58 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants bada_status width(1) "" {
-        BADA_0_w = 0 "Status bit unchanged";
         BADA_0_r = 0 "No Interrupt.";
         BADA_1_r = 1 "Bad Access";
-        BADA_1_w = 1 "Status is cleared";
     };
 
     constants cerr_status width(1) "" {
-        CERR_0_w = 0 "Status bit unchanged";
         CERR_0_r = 0 "No Error";
-        CERR_1_w = 1 "Status is cleared";
         CERR_1_r = 1 "Card error";
     };
 
     constants admae_status width(1) "" {
-        ADMAE_0_w = 0 "Status bit unchanged";
         ADMAE_0_r = 0 "No Interrupt.";
-        ADMAE_1_w = 1 "Status is cleared";
         ADMAE_1_r = 1 "ADMA error";
     };
 
     constants ace_status width(1) "" {
-        ACE_0_w = 0 "Status bit unchanged";
         ACE_0_r = 0 "No Error.";
         ACE_1_r = 1 "AutoCMD12 error";
-        ACE_1_w = 1 "Status is cleared";
     };
 
     constants deb_status width(1) "" {
         DEB_0_r = 0 "No Error";
-        DEB_0_w = 0 "Status bit unchanged";
-        DEB_1_w = 1 "Status is cleared";
         DEB_1_r = 1 "Data end bit error";
     };
 
     constants dcrc_status width(1) "" {
         DCRC_0_r = 0 "No Error.";
-        DCRC_0_w = 0 "Status bit unchanged";
         DCRC_1_r = 1 "Data CRC error";
-        DCRC_1_w = 1 "Status is cleared";
     };
 
     constants dto_status1 width(1) "" {
         DTO_0_r = 0 "No error.";
-        DTO_0_w = 0 "Status bit unchanged";
-        DTO_1_w = 1 "Status is cleared";
         DTO_1_r = 1 "Time out";
     };
 
     constants cie_status width(1) "" {
         CIE_0_r = 0 "No error.";
-        CIE_0_w = 0 "Status bit unchanged";
         CIE_1_r = 1 "Command index error";
-        CIE_1_w = 1 "Status is cleared";
     };
 
     constants ceb_status width(1) "" {
-        CEB_0_w = 0 "Status bit unchanged";
         CEB_0_r = 0 "No error.";
         CEB_1_r = 1 "Command end bit error";
-        CEB_1_w = 1 "Status is cleared";
     };
 
     constants ccrc_status width(1) "" {
         CCRC_0_r = 0 "No Error.";
-        CCRC_0_w = 0 "Status bit unchanged";
-        CCRC_1_w = 1 "Status is cleared";
         CCRC_1_r = 1 "Command CRC error";
     };
 
     constants cto_status width(1) "" {
-        CTO_0_w = 0 "Status bit unchanged";
         CTO_0_r = 0 "No error";
         CTO_1_r = 1 "Time Out";
-        CTO_1_w = 1 "Status is cleared";
     };
 
     constants erri_status width(1) "" {
@@ -902,17 +846,13 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants bsr_status width(1) "" {
-        BSR_0_w = 0 "Status bit unchanged";
         BSR_0_r = 0 "No Interrupt.";
-        BSR_1_w = 1 "Status is cleared";
         BSR_1_r = 1 "Boot status received interrupt.";
     };
 
     constants obi_status width(1) "" {
         OBI_0_r_1 = 0 "No Out-Of-Band interrupt.";
-        OBI_0_w = 0 "Status bit unchanged";
         OBI_1_r_1 = 1 "Interrupt Out-Of-Band occurs";
-        OBI_1_w = 1 "Status is cleared";
     };
 
     constants cirq_status width(1) "" {
@@ -921,58 +861,42 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants crem_status width(1) "" {
-        CREM_0_w = 0 "Status bit unchanged";
         CREM_0_r = 0 "Card state stable or Debouncing";
         CREM_1_r = 1 "Card removed";
-        CREM_1_w = 1 "Status is cleared";
     };
 
     constants cins_status1 width(1) "" {
         CINS_0_r_1 = 0 "Card state stable or debouncing";
-        CINS_0_w = 0 "Status bit unchanged";
-        CINS_1_w = 1 "Status is cleared";
         CINS_1_r_1 = 1 "Card inserted";
     };
 
     constants brr_status width(1) "" {
         BRR_0_r = 0 "Not Ready to read buffer";
-        BRR_0_w = 0 "Status bit unchanged";
         BRR_1_r = 1 "Ready to read buffer";
-        BRR_1_w = 1 "Status is cleared";
     };
 
     constants bwr_status width(1) "" {
-        BWR_0_w = 0 "Status bit unchanged";
         BWR_0_r = 0 "Not Ready to write buffer";
         BWR_1_r = 1 "Ready to write buffer";
-        BWR_1_w = 1 "Status is cleared";
     };
 
     constants dma_status width(1) "" {
         DMA_0_r = 0 "Dma interrupt detected";
-        DMA_0_w = 0 "Status bit unchanged";
-        DMA_1_w = 1 "Status is cleared";
         DMA_1_r = 1 "No dma interrupt";
     };
 
     constants bge_status width(1) "" {
         BGE_0_r = 0 "No block gap event";
-        BGE_0_w = 0 "Status bit unchanged";
-        BGE_1_w = 1 "Status is cleared";
         BGE_1_r = 1 "Transaction stopped at block gap";
     };
 
     constants tc_status width(1) "" {
-        TC_0_w = 0 "Status bit unchanged";
         TC_0_r = 0 "No transfer complete";
-        TC_1_w = 1 "Status is cleared";
         TC_1_r = 1 "Data transfer complete";
     };
 
     constants cc_status width(1) "" {
-        CC_0_w = 0 "Status bit unchanged";
         CC_0_r = 0 "No Command complete";
-        CC_1_w = 1 "Status is cleared";
         CC_1_r = 1 "Command complete";
     };
     
@@ -1123,23 +1047,17 @@ device omap44xx_mmchs1 msbfirst ( addr base ) "" {
     };
 
     constants vs18_status width(1) "" {
-        VS18_0_w = 0 "1.8 V not supported";
         VS18_0_r = 0 "1.8 V not supported";
         VS18_1_r = 1 "1.8 V supported";
-        VS18_1_w = 1 "1.8 V supported";
     };
 
     constants vs30_status width(1) "" {
         VS30_0_r = 0 "3.0 V not supported";
-        VS30_0_w = 0 "3.0 V not supported";
-        VS30_1_w = 1 "3.0 V supported";
         VS30_1_r = 1 "3.0 V supported";
     };
 
     constants vs33_status width(1) "" {
         VS33_0_r = 0 "3.3 V not supported";
-        VS33_0_w = 0 "3.3 V not supported";
-        VS33_1_w = 1 "3.3 V supported";
         VS33_1_r = 1 "3.3 V supported";
     };
 
diff --git a/devices/sdhc.dev b/devices/sdhc.dev
new file mode 100644 (file)
index 0000000..78b3851
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * sdhc.dev
+ *
+ * DESCRIPTION: SD Host Controller
+ *
+ * See:
+ *   SD Specifications Part A2: SD Host Controller Simplified Specification
+ *   Version 3.00, February 25, 2011. 
+ *   Technical Committee, SD Association
+ *
+ * Note that the specification specifies 16-bit registers.  Here we
+ * merge adjacent registers into 32-bit ones, so they are accessed
+ * two-at-a-time as 32-bit words.  This is how they are implemented on
+ * the TI OMAP SoCs, for example.
+ */
+ device sdhc msbfirst (addr base) "SD Host Controller" {
+
+     //
+     // Command formats (the non-trival ones)
+     //
+     // The following section numbers refer to: 
+     //   SD Specifications Part 1: Physical Layer Simplified Specification
+     //    Version 3.01, May 18, 2010.
+     //    Technical Committee, SD Card Association     
+     //
+
+     // 4.7.4
+     datatype cmd4 msbfirst(32) "SET_DSR command" {
+        dsr    16      "DSR value";
+        _      16;
+     };
+     
+     datatype rcacmd msbfirst(32) "Commands 7,9,10,13,15,55" {
+        rca    16      "RCA value";
+        _      16;
+     };
+     
+     datatype cmd8 msbfirst(32) "SEND_IF_COND command" {
+         _     20 mbz;
+         vhs   4        "Voltage supplied (VHS)";
+         pattern 8       "Check pattern";
+     };
+
+
+
+     //
+     // Host controller registers
+     //
+     // The following section numbers refer to: 
+     //   SD Specifications Part A2: SD Host Controller Simplified Specification
+     //   Version 3.00, February 25, 2011. 
+     //   Technical Committee, SD Association
+     //
+
+     // 2.2.1
+     register sdmasa rw addr(base, 0x00) "SDMA system address" 
+         type(uint32);
+
+     register arg2 rw also addr(base, 0x00) "Argument 2"
+         type(uint32);
+         
+     // 2.2.2/3
+     register blckcnt rw addr(base, 0x04) "Block count" {
+         nblk           16      "Block count";
+         _              1 mbz;
+         hsbb           3       "Host SDMA buffer boundary (4k . 2^x)";
+         blen           12      "Transfer block size (bytes)";
+     };
+     
+     // 2.2.4
+     register arg1 rw addr(base, 0x08) "Argument 1" 
+         type(uint32);
+
+     // 2.2.5/6
+     constants auto_en "Auto command enable values" {
+        auto_en_dis = 0b00     "Auto Command Disabled";
+        auto_en_12  = 0b01     "Auto CMD12 Enable";
+        auto_en_23  = 0b10     "Auto CMD23 Enable";
+     };
+     constants cmd_tp "Command type" {
+        cmd_tp_abrt = 0b11     "Abort CMD12, CMD52 for writing I/O Abort";
+        cmd_tp_rsme = 0b10     "Resume CMD52 for writing Function Select";
+        cmd_tp_susp = 0b01     "Suspend CMD52 for writing Bus Suspend";
+        cmd_tp_norm = 0b00     "Normal; other commands";
+     };
+     constants rsp_tp "Response type" {
+        rsp_tp_none = 0b00     "No response";
+        rsp_tp_136  = 0b01     "Response length 136";
+        rsp_tp_48   = 0b10     "Response length 48";
+        rsp_tp_48cb = 0b11     "Response length 48 check busy after response";
+     };
+     register ctm rw addr(base, 0x0C) "Command and transfer mode" {
+         _              2 mbz;
+         index          6       "Command index";
+         cmd_type       2 type(cmd_tp) "Command type";
+         dp             1       "Data present select";
+         cice           1       "Command index check enable";
+         ccce           1       "Command CRC check enable";
+         _              1 mbz;
+         rsp_type       2       "Response type select";
+         _              10 mbz;
+         msbs           1       "Multi/single block select (1=multi)";
+         ddir           1       "Data transfer direction select (1=read)";
+         acen           2 type(auto_en) "Auto command enable";
+         bce            1       "Block count enable";
+         de             1       "DMA enable";
+     };
+     
+     // 2.2.7
+     regarray resp rw addr(base, 0x10)[4] "Response"
+         type(uint32);
+     
+     // 2.2.8
+     register bdp rw addr(base, 0x20) "Buffer data port"
+         type(uint32);
+     
+     // 2.2.9
+     register ps ro addr(base, 0x24) "Present state" {
+         _              7 mbz;
+         clsl           1       "CMD line signal level";
+         dlsl           4       "DAT[3:0] line signal level";
+         wp             1       "Write protect switch pin level (0=ro)";
+         cdpl           1       "Card detect pin level (1=present)";
+         css            1       "Card state stable";
+         cins           1       "Card inserted";
+         _              4 mbz;
+         bre            1       "Buffer read enable";
+         bwe            1       "Buffer write enable";
+         rta            1       "Read transfer active";
+         wta            1       "Write transfer active";
+         _              4 mbz;
+         rtr            1       "Re-tuning request";
+         dla            1       "DAT line active";
+         dati           1       "Command inhibit (DAT)";
+         cmdi           1       "Command inhibit (CMD)";
+     };
+     
+     // 2.2.10-13
+     constants voltage "Bus voltage select" {
+        voltage_33 = 0b111     "3.3V (typ.)";
+        voltage_30 = 0b110     "3.0V (typ.)";
+        voltage_18 = 0b101     "1.8V (typ.)";
+     };
+     register hctl rw addr(base, 0x28) "Host control" {
+         _              5 mbz;
+         rem            1       "Wakeup event enable on SD card removal";
+         ins            1       "Wakeup event enable on SD card insertion";
+         iwe            1       "Wakeup event enable on card interrupt";
+         _              4 mbz;
+         ibg            1       "Interrupt at block gap";
+         rwc            1       "Read wait control";
+         cr             1       "Continue request";
+         sbgr           1       "Stop at block gap request";
+         _              4 mbz;
+         sdvs           3 type(voltage) "SD bus voltage select";
+         sdbp           1       "SD bus power";
+         cdss           1       "Card detect signal selection";
+         cdtl           1       "Card detect test level";
+         edtw           1       "Extended data transfer width";
+         dmas           2       "DMA select";
+         hspe           1       "High speed enable";
+         dtw            1       "Data transfer width";
+         lc             1       "LED control";
+     };
+
+     // 2.2.14-16
+     register sysctl rw addr(base, 0x2C) "System control" {
+         _              5 mbz;
+         srd            1       "Software reset for DAT line";
+         src            1       "Software reset for CMD line";
+         sra            1       "Software reset for all";
+         _              4 mbz;
+         dto            4       "Data timeout counter value";
+         clkd           10      "SDCLK frequency select";
+         cgs            1       "Clock generator select";
+         _              2 mbz;
+         cen            1       "SD clock enable";
+         ics            1 ro    "Internal clock stable";
+         ice            1       "Internal clock enable";
+     };
+     
+     // 2.2.17/18
+     register stat addr(base, 0x30) "Interrupt status" {
+        // 4 bits in the spec, but we have two bits in the OMAP 44xx
+        // adaptor which we also specify here.  Might need to change
+        // this if we encounter another SDHC reader with different
+        // use of these bits. 
+        vses           2 rw    "Vendor specific error status";
+        bada           1 rw1c  "Bad access to data space";
+        cerr           1 rw1c  "Card error";
+         _              1 mbz;
+         te             1 rw1c  "Tuning error";
+         admae          1 rw1c  "ADMA error";
+         ace            1 rw1c  "Auto CMD error";
+         cle            1 rw1c  "Current limit error";
+         deb            1 rw1c  "Data end bit error";
+         dcrc           1 rw1c  "Data CRC error";
+         dto            1 rw1c  "Data timeout error";
+         cie            1 rw1c  "Command index error";
+         ceb            1 rw1c  "Command end bit error";
+         ccrc           1 rw1c  "Command CRC error";
+         cto            1 rw1c  "Command timeout error";
+         erri           1 ro    "Error interrupt";
+         _              2 mbz;
+         rte            1 ro    "Re-tuning event";
+         intc           1 ro    "INT_C";
+         intb           1 ro    "INT_B";
+         inta           1 ro    "INT_A";
+         cirq           1 ro    "Card interrupt";
+         crem           1 rw1c  "Card removal";
+         cins           1 rw1c  "Card insertion";
+         brr            1 rw1c  "Buffer read ready";
+         bwr            1 rw1c  "Buffer write ready";
+         dma            1 rw1c  "DMA interrupt";
+         bge            1 rw1c  "Block gap event";
+         tc             1 rw1c  "Transfer complete";
+         cc             1 rw1c  "Command complete";
+     };
+
+     
+
+     // 2.2.19-22
+     regtype ir "Interrupt register" {
+        // 4 bits in the spec, but we have two bits in the OMAP 44xx
+        // adaptor which we also specify here.  Might need to change
+        // this if we encounter another SDHC reader with different
+        // use of these bits. 
+        vses           2 rw    "Vendor specific error status";
+        bada           1 rw    "Bad access to data space";
+        cerr           1 rw    "Card error";
+         _              1 mbz;
+         te             1 rw    "Tuning error";
+         admae          1 rw    "ADMA error";
+         ace            1 rw    "Auto CMD error";
+         cle            1 rw    "Current limit error";
+         deb            1 rw    "Data end bit error";
+         dcrc           1 rw    "Data CRC error";
+         dto            1 rw    "Data timeout error";
+         cie            1 rw    "Command index error";
+         ceb            1 rw    "Command end bit error";
+         ccrc           1 rw    "Command CRC error";
+         cto            1 rw    "Command timeout error";
+         _              3 mbz;
+         rte            1 rw    "Re-tuning event";
+         intc           1 rw    "INT_C";
+         intb           1 rw    "INT_B";
+         inta           1 rw    "INT_A";
+         cirq           1 rw    "Card interrupt";
+         crem           1 rw    "Card removal";
+         cins           1 rw    "Card insertion";
+         brr            1 rw    "Buffer read ready";
+         bwr            1 rw    "Buffer write ready";
+         dma            1 rw    "DMA interrupt";
+         bge            1 rw    "Block gap event";
+         tc             1 rw    "Transfer complete";
+         cc             1 rw    "Command complete";
+     };
+
+     register ie addr(base, 0x34) "Interrupt enable" 
+         type(ir);
+     register ise addr(base, 0x38) "Interrupt signal enable" 
+         type(ir);
+
+     // 2.2.23-24
+     constants uhs_mode "UHS mode" {
+        uhs_sdr12      = 0b000         "SDR12";
+        uhs_sdr25      = 0b001         "SDR25";
+        uhs_sdr50      = 0b010         "SDR50";
+        uhs_sdr104     = 0b011         "SDR104";
+        uhs_ddr50      = 0b100         "DDR50";
+     };
+     register aces addr(base, 0x3c) "Auto CMD error status / Host control 2" {
+         pve            1 rw    "Preset value enable";
+         aie            1 rw    "Asynchronous interrupt enable";
+         _              6 mbz;
+         scs            1 rw    "Sampling clock select";
+         et             1 rw    "Execute tuning";
+         dss            2 rw    "Driver strength select";
+         lvse           1 rw    "1.8V signaling enable";
+         ums            3 rw type(uhs_mode) "UHS mode select";
+         _              8 mbz;
+         cni            1 ro    "Command not issued by Auto CMD12 error";
+         _              2 mbz;
+         acie           1 ro    "Auto CMD index error";
+         acebe          1 ro    "Auto CMD end bit error";
+         acce           1 ro    "Auto CMD CRC error";
+         acte           1 ro    "Auto CMD timeout error";
+         acne           1 ro    "Auto CMD12 not executed";
+     };
+
+     // 2.2.25
+     // This register is, bizarrely, writeable on the OMAP44xx, and
+     // needs to be written to configure the controller. 
+     constants slot_tp "Slot type" { 
+        slot_rem = 0b00        "Removable card slot";
+        slot_emb = 0b01        "Embedded slot for one device";
+        slot_shr = 0b10        "Shared bus slot";
+     };
+     register capa rw addr(base, 0x40) "Capability register A" {
+         slottp         2 type(slot_tp) "Slot type";
+         ais            1       "Asynchronous interrupt support";
+         bit64          1       "64-bit system bus support";
+         _              1 mbz;
+         vs18           1       "Voltage support 1.8V";
+         vs30           1       "Voltage support 3.0V";
+         vs33           1       "Voltage support 3.3V";
+         srs            1       "Suspend/resume support";
+         ds             1       "SDMA support";
+         hss            1       "High speed support";
+         _              1 mbz;
+         ad2s           1       "ADMA2 support";
+         bit8           1       "8-bit support for embedded device";
+         mbl            2       "Max block length";
+         bcf            8       "Base clock frequency for SD clock";
+         tcu            1       "Timeout clock unit";
+         _              1 mbz;
+         tcf            6       "Tileout clock frequency";
+     };
+
+     register capb ro addr(base, 0x44) "Capability register B" {
+         _              8 mbz;
+         cm             8       "Clock multiplier";
+         rtm            2       "Re-tuning modes";
+         utsdr50        1       "Use tuning for SDR50";
+         _              1 mbz;
+         tcrt           4       "Timer count for re-tuning";
+         _              1 mbz;
+         dtd            1       "Driver type D support";
+         dtc            1       "Driver type C support";
+         dta            1       "Driver type A support";
+         _              1 mbz;
+         ddr50          1       "DDR50 support";
+         sdr104         1       "SDR104 support";
+         sdr50          1       "SDR50 support";
+     };
+
+     // 2.2.26
+     register mcc ro addr(base, 0x48) "Maximum current capabilities" {
+         _              8 mbz;
+         mc18           8       "Maximum current for 1.8V";
+         mc30           8       "Maximum current for 3.0V";
+         mc33           8       "Maximum current for 3.3V";
+     };
+
+     // 2.2.27
+     register fer wo addr(base, 0x50) "Force event register" {
+         vses           4 wo    "Vendor specific error status";
+         _              2 mbz;
+         ae             1 wo    "ADMA error";
+         ace            1 wo    "Auto CMD error";
+         cle            1 wo    "Current limit error";
+         debe           1 wo    "Data end bit error";
+         dce            1 wo    "Data CRC error";
+         dte            1 wo    "Data timeout error";
+         cie            1 wo    "Command index error";
+         cebe           1 wo    "Command end bit error";
+         cce            1 wo    "Command CRC error";
+         cte            1 wo    "Command timeout error";
+         _              8 mbz;
+         cni            1 wo    "Command not issued by Auto CMD12 error";
+         _              2 mbz;
+         acie           1 wo    "Auto CMD index error";
+         acebe          1 wo    "Auto CMD end bit error";
+         acce           1 wo    "Auto CMD CRC error";
+         acte           1 wo    "Auto CMD timeout error";
+         acne           1 wo    "Auto CMD12 not executed";
+     };
+         
+     // 2.2.29
+     register admaes ro addr(base, 0x54) "ADMA error status" {
+         _              29 mbz;
+         lme            1       "ADMA length mismatch error";
+         aes            2       "ADMA error state";
+     };
+
+     // 2.2.30
+     register admasl rw addr(base, 0x58) "ADMA system address low"
+         type(uint32);
+     register admash rw addr(base, 0x5C) "ADMA system address high"
+         type(uint32);
+
+     // 
+     // We do not, at present, implement the Preset Value registers.
+     //
+     
+     // 2.2.32
+     register sbc rw addr(base, 0xE0) "Shared bus control" {
+         _              1 mbz;
+         bepc           7 rw    "Back-end power control";
+         _              1 mbz;
+         ips            3 rw    "Interrupt pin select";
+         _              1 mbz;
+         cps            3 rw    "Clock pin select";
+         _              1 mbz;
+         bwp            7 ro    "Bus width preset";
+         _              2 mbz;
+         niip           2 ro    "Number of interrupt input pins";
+         _              1 mbz;
+         ncp            3 ro    "Number of clock pins";
+     };
+
+     // 2.2.33/34
+     register rev rw addr(base, 0xFC) "Version / Slot int. status" {
+         vrev           8 ro    "Vendor version number";
+         srev           8 ro    "Specification version number";
+         _              8 mbz;
+         slots          8       "Interrupt status per slot";
+     };
+
+ };
diff --git a/devices/ti_i2c.dev b/devices/ti_i2c.dev
new file mode 100644 (file)
index 0000000..4ad2fbd
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * ti_i2c.dev
+ *
+ * DESCRIPTION: TI I2C controller registers.
+ * 
+ * Section numbers refer to OMAP4460 ES1.x PUBLIC TRM vQ
+ *
+ * (I think the I2C controllers in the OMAP4460 match the standard TI I2C) -SG
+ */
+
+device ti_i2c msbfirst (addr b) "TI I2C controller" {
+    // Tables 23-33 and 23-35
+    register revnb_lo ro addr(b, 0x0) "Revision number (low part)" type(uint16);
+    register revnb_hi ro addr(b, 0x4) "Revision number (high part)" type(uint16);
+
+    constants clkact "clock activity" {
+        clk_off = 0b00 "Both clocks can be off";
+        clk_ocp = 0b01 "Only OCP clock must be kept active";
+        clk_sys = 0b10 "Only system clock must be kept active";
+        clk_act = 0b11 "Both clocks must be active";
+    };
+
+    constants idlemode "idle mode" {
+        idlemode_forceidle = 0b00 "Force Idle";
+        idlemode_noidle    = 0b01 "No Idle";
+        idlemode_smartidle = 0b10 "Smart Idle";
+        idlemode_smartwkup = 0b11 "Smart Idle & Wakeup";
+    };
+
+    // Table 23-37
+    register sysc rw addr(b, 0x10) "System Configuration" {
+        _           6 rsvd;
+        clkactivity 2 type(clkact) "Clock activity selection";
+        _           3 rsvd;
+        idlemode    2 type(idlemode) "Idle mode selection";
+        enawakeup   1 "Enable wakeup control";
+        srst        1 "SoftReset";
+        autoidle    1 "Autoidle";
+    };
+
+    // Tables 23-39 and 23-41
+    regtype irqstatus "interrupt status vector" {
+        _    1 rsvd;
+        xdr  1    "Transmit draining";
+        rdr  1    "Receive draining";
+        bb   1 ro "Bus busy";
+        rovr 1    "Receive overrun";
+        xudf 1    "Transmit underflow";
+        aas  1    "Address recognized as slave IRQ status";
+        bf   1    "Bus free";
+        aerr 1    "Access error";
+        stc  1    "Start condition";
+        gc   1    "General call";
+        xrdy 1    "Transmit data ready";
+        rrdy 1    "Receive data ready";
+        ardy 1    "Register access ready";
+        nack 1    "No acknowledgement";
+        al   1    "Arbitration lost";
+    };
+    register irqstatus_raw rw addr(b, 0x24) "Per-event raw interrupt status vector" 
+        type(irqstatus);
+    register irqstatus rw1c addr(b, 0x28) "Per-event enabled interrupt status vector" 
+        type(irqstatus);
+
+    // Tables 23-43 and 23-45
+    regtype irqenable "interrupt enable vector" {
+        _    1 rsvd;
+        xdr_ie  1    "Transmit draining";
+        rdr_ie  1    "Receive draining";
+        _       1 rsvd;
+        // NOTE: rovr and xudf don't have _ie in OMAP TRM -SG
+        rovr_ie 1    "Receive overrun";
+        xudf_ie 1    "Transmit underflow";
+        aas_ie  1    "Address recognized as slave IRQ status";
+        bf_ie   1    "Bus free";
+        aerr_ie 1    "Access error";
+        stc_ie  1    "Start condition";
+        gc_ie   1    "General call";
+        xrdy_ie 1    "Transmit data ready";
+        rrdy_ie 1    "Receive data ready";
+        ardy_ie 1    "Register access ready";
+        nack_ie 1    "No acknowledgement";
+        al_ie   1    "Arbitration lost";
+    };
+    register irqenable_set rw addr(b, 0x2C) "Per-event interrupt enable bit vector"
+        type(irqenable);
+    register irqenable_clr rw addr(b, 0x30) "Per-event interrupt clear bit vector"
+        type(irqenable);
+
+    regtype wakeupen "per-event wakeup enable" {
+        _    1 rsvd;
+        xdr  1    "Transmit draining";
+        rdr  1    "Receive draining";
+        _    1 rsvd;
+        rovr 1    "Receive overrun";
+        xudf 1    "Transmit underflow";
+        aas  1    "Address recognized as slave IRQ status";
+        bf   1    "Bus free";
+        _    1 rsvd;
+        stc  1    "Start condition";
+        gc   1    "General call";
+        _    1 rsvd;
+        drdy 1    "Receive/Transmit data ready";
+        ardy 1    "Register access ready";
+        nack 1    "No acknowledgement";
+        al   1    "Arbitration lost";
+    };
+
+    // Table 23-47
+    register we rw addr(b, 0x34) "Wakeup enable vector" type(wakeupen);
+
+    // Tables 23-49, 23-51, 23-53, and 23-55
+    // NOTE: nomenclature doesn't match OMAP TRM
+    regtype dmaen "DMA enable" {
+        _  15 rsvd;
+        en 1 "Enable DMA channel";
+    };
+    register dmarxenable_set addr(b, 0x38) "Per-event DMA RX enable"
+        type(dmaen);
+    register dmatxenable_set addr(b, 0x3C) "Per-event DMA TX enable"
+        type(dmaen);
+    register dmarxenable_clr addr(b, 0x40) "Per-event DMA RX enable clear"
+        type(dmaen);
+    register dmatxenable_clr addr(b, 0x44) "Per-event DMA TX enable clear"
+        type(dmaen);
+
+    // Tables 23-57 and 23-59
+    register dmarxwake_en addr(b, 0x48) "Per-event DMA RX wakeup enable"
+        type(wakeupen);
+    register dmatxwake_en addr(b, 0x4C) "Per-event DMA TX wakeup enable"
+        type(wakeupen);
+
+    // Table 23-61 
+    register ie rw addr(b, 0x84) "Interrupt enable vector (legacy)"
+        type(irqenable);
+
+    // dummy constants for polling stat flags
+    constants irqstatus_flags "irqstatus bitmasks" {
+        irq_flag_xdr  =0b1110    "Transmit draining";
+        irq_flag_rdr  =0b1101    "Receive draining";
+        irq_flag_bb   =0b1100    "Bus busy";
+        irq_flag_rovr =0b1011    "Receive overrun";
+        irq_flag_xudf =0b1010    "Transmit underflow";
+        irq_flag_aas  =0b1001    "Address recognized as slave IRQ status";
+        irq_flag_bf   =0b1000    "Bus free";
+        irq_flag_aerr =0b0111    "Access error";
+        irq_flag_stc  =0b0110    "Start condition";
+        irq_flag_gc   =0b0101    "General call";
+        irq_flag_xrdy =0b0100    "Transmit data ready";
+        irq_flag_rrdy =0b0011    "Receive data ready";
+        irq_flag_ardy =0b0010    "Register access ready";
+        irq_flag_nack =0b0001    "No acknowledgement";
+        irq_flag_al   =0b0000    "Arbitration lost";
+    };
+    // Table 23-63
+    register stat rw1c addr(b, 0x88) "Interrupt status vector (legacy)"
+        type(irqstatus);
+
+    // Table 23-65
+    register syss rw addr(b, 0x90) "System status" {
+        _     15 rsvd;
+        rdone 1 rw "Reset done";
+    };
+
+    // Table 23-67
+    register buf rw addr(b, 0x94) "Buffer Configuration" {
+        rdma_en    1 "Receive DMA enable";
+        rxfifo_clr 1 "Receive FIFO clear";
+        rxtrsh     6 "Threshold value for FIFO buffer in RX mode";
+        xdma_en    1 "Transmit DMA enable";
+        txfifo_clr 1 "Transmit FIFO clear";
+        txtrsh     6 "Threshold value for FIFO buffer in TX mode";
+    };
+
+    // Table 23-69
+    // NOTE: writing 0 to cnt equals to a transfer of 65536 bytes; this means
+    // that software has to disallow 0-byte transfers. -SG
+    register cnt rw addr(b, 0x98) "Data counter" type(uint16);
+
+    // Table 23-71
+    register data rw addr(b, 0x9C) "Data access" {
+        _    8 rsvd;
+        data 8 "Transmit/Receive data FIFO endpoint";
+    };
+
+    // Table 23-73
+    constants opmode "Operation Mode" {
+        opmode_fs   = 0b00 "I2C Fast/Standard Mode";
+        opmode_hs   = 0b01 "I2C High Speed Mode";
+        opmode_sccb = 0b10 "SCCB Mode";
+    };
+    register con rw addr(b, 0xA4) "Configuration" {
+        en     1 "module enable";
+        _      1 rsvd;
+        opmode 2 type(opmode) "Operation mode selection";
+        stb    1 "Start byte mode";
+        mst    1 "Master/slave mode";
+        trx    1 "Transmitter/Receiver mode";
+        xsa    1 "Expand Slave Address";
+        xoa0   1 "Expand Own address 0";
+        xoa1   1 "Expand Own address 1";
+        xoa2   1 "Expand Own address 2";
+        xoa3   1 "Expand Own address 3";
+        _ 2 rsvd;
+        stp    1 "Stop condition";
+        stt    1 "Start condition";
+    };
+
+    // Table 23-75
+    register oa rw addr(b, 0xA8) "Own address" {
+        mcode 3 "Master Code";
+        _     3 rsvd;
+        oa    10 "Own addres";
+    };
+
+    // Table 23-77
+    register sa rw addr(b, 0xAC) "Slave address" {
+        _  6 rsvd;
+        sa 10 "Slave address";
+    };
+
+    // Table 23-79
+    register psc rw addr(b, 0xB0) "Clock Prescaler" {
+        _ 8 rsvd;
+        psc 8 "Fast/Standard mode prescale sampling clock divider [/(psc+1)]";
+    };
+
+    // Tables 23-81 and 23-83
+    regtype scltime "SCL time" {
+        hsscl 8 "High Speed mode SCL time";
+        scl   8 "Fast/Standard mode SCL time";
+    };
+    register scll rw addr(b, 0xB4) "SCL Low Time" type(scltime);
+    register sclh rw addr(b, 0xB8) "SCL High Time" type(scltime);
+
+    // Table 23-85
+    constants testmode "Test mode" {
+        test_functional = 0b00 "Functional mode (default)";
+        test_loopback   = 0b11 "Loop back mode select + SDA/SCL IO mode select";
+        test_sclcnttest = 0b10 "Test of SCL counters";
+    };
+    register systest rw addr(b, 0xBC) "System Test" {
+        st_en      1 "System test enable";
+        free       1 "Free running mode (on breakpoint)";
+        tmode      2 type(testmode) "Test mode select";
+        ssb        1 "Set status bits from 0 to 14";
+        _          2 rsvd;
+        scl_i_func 1 ro "SCL line input value";
+        scl_o_func 1 ro "SCL line output value";
+        sda_i_func 1 ro "SDA line input value";
+        sda_o_func 1 ro "SDA line output value";
+        sccb_e_o   1 rw "SCCB_E line sense output value";
+        scl_i      1 ro "SCL line sense input value";
+        scl_o      1 rw "SCL line drive output value";
+        sda_i      1 ro "SDA line sense input value";
+        sda_o      1 rw "SDA line drive output value";
+    };
+
+    // Table 23-87
+    register bufstat ro addr(b, 0xC0) "Buffer Status" {
+        fifodepth 2 "Internal FIFO buffers depth";
+        rxstat    6 "RX buffer status";
+        _         2 rsvd;
+        txstat    6 "TX buffer status";
+    };
+
+    // Tables 23-89, 23-91, and 23-93
+    regtype ownaddr "own address" {
+        _  6 rsvd;
+        oa 10 "Own address";
+    };
+    register oa1 addr(b, 0xC4) "Own Address 1" type(ownaddr);
+    register oa2 addr(b, 0xC8) "Own Address 2" type(ownaddr);
+    register oa3 addr(b, 0xCC) "Own Address 3" type(ownaddr);
+
+    // Table 23-95
+    register actoa ro addr(b, 0xD0) {
+        _       12 rsvd;
+        oa3_act 1 "Own address 3 active";
+        oa2_act 1 "Own address 2 active";
+        oa1_act 1 "Own address 1 active";
+        oa0_act 1 "Own address 0 active";
+    };
+
+    // Table 23-97
+    register sblock rw addr(b, 0xD4) "Clock Blocking Enable" {
+        _ 12 rsvd;
+        oa3_en 1 "Own address 3 clock blocking enable";
+        oa2_en 1 "Own address 2 clock blocking enable";
+        oa1_en 1 "Own address 1 clock blocking enable";
+        oa0_en 1 "Own address 0 clock blocking enable";
+    };
+};
diff --git a/devices/ti_twl6030.dev b/devices/ti_twl6030.dev
new file mode 100644 (file)
index 0000000..a213d43
--- /dev/null
@@ -0,0 +1,125 @@
+
+/*
+ * Copyright (c) 2012, ETH Zurich. All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+/*
+ * ti_twl6030.dev
+ *
+ * DESCRIPTION: TI TWL6030 Power Companion IC
+ * 
+ * Section numbers refer to TWL6030 Register Map
+ * (Literature Number: SWCU084)
+ *
+ * Talking to this device will usually go over I2C, but it's still helpful to
+ * have the register definitions
+ *
+ * TODO: need to add everything other than VMMC -SG
+ */
+
+device ti_twl6030 msbfirst (addr b) "TI TWL6030 Power Companion (via I2C)" {
+    // dummy set of constants representing the I2C addresses of the different
+    // register groups
+    constants i2c_addrs "Physical (I2C) addresses" {
+        i2c_addr_vmmc = 0x48 "VMMC I2C address";
+    };
+
+
+    regtype cfg_grp "Group Configuration" {
+        _       5 rsvd;
+        grp_mod 1 "Modem Power Group";
+        grp_con 1 "Connectivity Power Group";
+        grp_app 1 "Application Power Group";
+    };
+
+    constants transition_cmd "Transition Command" {
+        tcmd_off = 0b00 "Off";
+        tcmd_ams = 0b01 "Sleep/Active";
+        // 0b10 is reserved
+        tcmd_act = 0b11 "Active";
+    };
+    regtype cfg_trans "Transition Configuration" { // not sure about name, guessing -SG
+        _      2 rsvd;
+        off    2 type(transition_cmd) "off state";
+        sleep  2 type(transition_cmd) "sleep state";
+        active 2 type(transition_cmd) "active state";
+    };
+
+    constants pwrstate "Power State" {
+        pwr_off   = 0b00 "Off";
+        pwr_on    = 0b01 "On";
+        pwr_off_2 = 0b10 "Off";
+        pwr_sleep = 0b11 "Sleep";
+    };
+
+    regtype cfg_state_w "State configuration (write)" {
+        grp_mod 1 "Set if apply state to modem power group";
+        grp_con 1 "Set if apply state to connectivity power group";
+        grp_app 1 "Set if apply state to application power group";
+        _       3 rsvd;
+        state   2 type(pwrstate) "Resource state to apply";
+    };
+
+    regtype cfg_state_r "State configuration (read)" {
+        mod_state 2 type(pwrstate) "Resource state for modem power group";
+        con_state 2 type(pwrstate) "Resource state for connectivity power group";
+        app_state 2 type(pwrstate) "Resource state for application power group";
+        state     2 type(pwrstate) "Resource state after power group arbitration";
+    };
+
+    constants wr "Warm reset" {
+        wr_reload_dflt = 0b0 "Reload default VSEL value on warm reset";
+        wr_keep        = 0b1 "Keep voltage configuration settings on warm reset";
+    };
+    // Table 121
+    constants vsel "Voltage selector" {
+        v0v0 = 0b00000 "0.0V";
+        v1v0 = 0b00001 "1.0V";
+        v1v1 = 0b00010 "1.1V";
+        v1v2 = 0b00011 "1.2V";
+        v1v3 = 0b00100 "1.3V";
+        v1v4 = 0b00101 "1.4V";
+        v1v5 = 0b00110 "1.5V";
+        v1v6 = 0b00111 "1.6V";
+        v1v7 = 0b01000 "1.7V";
+        v1v8 = 0b01001 "1.8V";
+        v1v9 = 0b01010 "1.9V";
+        v2v0 = 0b01011 "2.0V";
+        v2v1 = 0b01100 "2.1V";
+        v2v2 = 0b01101 "2.2V";
+        v2v3 = 0b01110 "2.3V";
+        v2v4 = 0b01111 "2.4V";
+        v2v5 = 0b10000 "2.5V";
+        v2v6 = 0b10001 "2.6V";
+        v2v7 = 0b10010 "2.7V";
+        v2v8 = 0b10011 "2.8V";
+        v2v9 = 0b10100 "2.9V";
+        v3v0 = 0b10101 "3.0V";
+        v3v1 = 0b10110 "3.1V";
+        v3v2 = 0b10111 "3.2V";
+        v3v3 = 0b11000 "3.3V";
+        // 0b11001 - 0b11110 reserved
+        v2v75 = 0b11111 "2.75V";
+    };
+    regtype cfg_voltage "Voltage configuration" {
+        wr_s 1 type(wr) "Warm reset sensitivity";
+        _    2 rsvd;
+        vsel 5 type(vsel) "Voltage to apply";
+    };
+
+    // VMMC registers
+    // Table 152
+    register vmmc_cfg_grp addr(b, 0x98) "VMMC Group Configuration" type(cfg_grp);
+    // Table 153
+    register vmmc_cfg_trans addr(b, 0x99) "VMMC Transition Configuration" type(cfg_trans);
+    // Table 154
+    register vmmc_cfg_state_w wo addr(b, 0x9A) "VMMC State Configuration (write format)" type(cfg_state_w);
+    // Table 155
+    register vmmc_cfg_state_r ro also addr(b, 0x9A) "VMMC State Configuration (read format)" type(cfg_state_r);
+    // Table 156
+    register vmmc_cfg_voltage addr(b, 0x9B) "VMMC Voltage Configuration" type(cfg_voltage);
+};
index eca7b32..2242f77 100644 (file)
@@ -127,6 +127,14 @@ errors kernel SYS_ERR_ {
 
     // ID capability
     failure ID_SPACE_EXHAUSTED  "ID space exhausted",
+
+    // I2C driver
+    // XXX: should not be in kernel
+    failure I2C_UNINITIALIZED           "Trying to use uninitialized i2c controller",
+    failure I2C_ZERO_LENGTH_MSG         "Zero byte transfers not allowed",
+    failure I2C_WAIT_FOR_BUS            "Wait for bus free timed out",
+    failure I2C_FAILURE                 "I2C subsystem failure",
+
 };
 
 // errors generated by libcaps
index 1c8857b..65b0c82 100644 (file)
@@ -366,7 +366,7 @@ let
                          "omap/omap44xx_id", 
                          "omap/omap44xx_emif",
                          "omap/omap44xx_gpio"],
-     addLibraries = [ "elf", "cpio", "fdif" ]
+     addLibraries = [ "elf", "cpio", "fdif", "mmchs" ]
      }                            
   
   ]
index b0d24a3..f04815e 100644 (file)
@@ -11,7 +11,8 @@
 
 #include <dev/pl130_gic_dev.h>
 #include <arm_hal.h>
-
+#include <gic.h>
 extern pl130_gic_t gic;
 extern uint32_t it_num_lines;
 
@@ -30,16 +31,6 @@ void  __attribute__((noreturn)) gic_disable_all_irqs(void)
     /* } */
 }
 
-
-// Helpers for enabling interrupts
-#define GIC_IRQ_PRIO_LOWEST       (0xF)
-#define GIC_IRQ_CPU_TRG_ALL       (0x3) // For two cores on the PandaBoard
-#define GIC_IRQ_CPU_TRG_BSP       (0x1)
-#define GIC_IRQ_EDGE_TRIGGERED    (0x1)
-#define GIC_IRQ_LEVEL_SENSITIVE   (0x0)
-#define GIC_IRQ_1_TO_N            (0x1)
-#define GIC_IRQ_N_TO_N            (0x0)
-
 /*
  * \brief Enable an interrupt
  *
diff --git a/kernel/include/arch/armv7/gic.h b/kernel/include/arch/armv7/gic.h
new file mode 100644 (file)
index 0000000..e08019c
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+ */
+
+#ifndef __GIC_H__
+#define __GIC_H__
+
+// Helpers for enabling interrupts
+#define GIC_IRQ_PRIO_LOWEST       (0xF)
+#define GIC_IRQ_CPU_TRG_ALL       (0x3) // For two cores on the PandaBoard
+#define GIC_IRQ_CPU_TRG_BSP       (0x1)
+#define GIC_IRQ_EDGE_TRIGGERED    (0x1)
+#define GIC_IRQ_LEVEL_SENSITIVE   (0x0)
+#define GIC_IRQ_1_TO_N            (0x1)
+#define GIC_IRQ_N_TO_N            (0x0)
+
+ #endif // __GIC_H__
\ No newline at end of file
diff --git a/kernel/include/arch/armv7/ti_i2c.h b/kernel/include/arch/armv7/ti_i2c.h
new file mode 100644 (file)
index 0000000..ecba14f
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+#ifndef __TI_I2C_H__
+#define __TI_I2C_H__
+
+enum i2c_flags {
+    I2C_RD = 0x0,
+    I2C_WR = 0x1,
+};
+
+struct i2c_msg {
+    // should not exceed 10 bits
+    uint16_t slave;
+    enum i2c_flags flags;
+    uint16_t length;
+    uint8_t *buf;
+};
+
+void ti_i2c_init(int i);
+errval_t ti_i2c_transfer(int i, struct i2c_msg *msgs, size_t msgcount);
+
+#endif // __TI_I2C_H__
diff --git a/usr/drivers/omap44xx/mmchs/Hakefile b/usr/drivers/omap44xx/mmchs/Hakefile
new file mode 100644 (file)
index 0000000..84a510b
--- /dev/null
@@ -0,0 +1,30 @@
+--------------------------------------------------------------------------
+-- Copyright (c) 2007-2013, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for omap44xx sd-card driver
+-- 
+--------------------------------------------------------------------------
+
+[
+    build library { target = "mmchs",
+                    cFiles = (find withSuffices [".c"]),
+                    mackerelDevices = [
+                        "ti_i2c",
+                        "ti_twl6030",
+                        "sdhc",
+                        "omap/omap44xx_mmchs",
+                        "omap/omap44xx_cm2",
+                        "omap/omap44xx_ctrlmod"
+                    ],
+                    addCFlags = [ "-DIN_KERNEL" ],
+                    addIncludes = [
+                        "../../../../kernel/include/",
+                        "../../../../kernel/include/arch/armv7/"
+                    ]
+                  }
+]
\ No newline at end of file
diff --git a/usr/drivers/omap44xx/mmchs/cm2.c b/usr/drivers/omap44xx/mmchs/cm2.c
new file mode 100644 (file)
index 0000000..4bf5430
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+
+#include <arm_hal.h>
+#include <omap44xx_cm2.h>
+#include <dev/omap/omap44xx_cm2_dev.h>
+
+static int cm2_clock_enabled = 0;
+static omap44xx_cm2_t cm2;
+
+#define CM2_BUF_SIZE (64*1024)
+char cm2_buf[CM2_BUF_SIZE];
+
+/*
+ * \brief Enable the clock
+ *
+ * See Free BSD: omap4_prcm_clks.c - omap4_clk_generic_activate()
+ *
+ * Module should be "fully functional" if ... 
+ * .. IDLEST reads as 0
+ * .. STBYST reads as 0 (x)
+ * Both of these fields are read-only values .. 
+ *
+ * (x) won't enable here, but I saw this enabled once .. 
+ *     I guess this is happening some time later .. 
+ *     I think we can flip this bit by disabling standby mode on the MMC
+ */
+void cm2_enable_hsmmc1(void)
+{
+    cm2_clock_enabled = 1;
+
+    omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_CLKSEL_wrf(&cm2, 0x0);
+
+    // Handling clock dependencies!
+    omap44xx_cm2_CM_DIV_M4_DPLL_PER_pr(cm2_buf, CM2_BUF_SIZE, &cm2);
+    printf("%s", cm2_buf);
+
+    // Disabling clock manually
+    omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_MODULEMODE_wrf(&cm2, 0x0);
+    
+    // Waiting for clock to be disabled ...
+    while (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_IDLEST_rdf(&cm2)!=0x3);
+
+    // Don't mess with the power controler unless we really believe 
+    // that the MMC is not powered up yet.
+    //
+    if (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_IDLEST_rdf(&cm2)==0x0) {
+
+        printf("cm2: Clock for HSMMC1 is already enabled\n");
+        return;
+    }
+
+    printf("cm2: Powering on HSMMC1 .. ");
+    omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_MODULEMODE_wrf(&cm2, 0x2);
+
+    volatile int cm2loop = 0;
+    while (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_IDLEST_rdf(&cm2)!=0) {
+
+        //        mmchs_wait_msec(1);
+
+        if (++cm2loop>1000) {
+            printf("failed\n");
+            panic("cm2: MMC power won't come up .. "
+                  "Don't know what to do, IDLEST and STBYST are ro");
+        }
+    }
+    printf("done (%d cycles)\n", cm2loop);
+
+    if (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_STBYST_rdf(&cm2)==0x1) {
+        printf("cm2: module MMC1 is in standby state\n");
+    }
+}
+
+void cm2_enable_i2c(int i2c_index)
+{
+    switch(i2c_index) {
+        case 1:
+            // enable i2c module
+            omap44xx_cm2_l4per_i2c1_clkctrl_modulemode_wrf(&cm2,
+                    omap44xx_cm2_modmode_swenabled);
+            // wait for module to get into functional state
+            while(omap44xx_cm2_l4per_i2c1_clkctrl_idlest_rdf(&cm2)
+                    !=omap44xx_cm2_idlest_functional);
+            break;
+        case 2:
+            // enable i2c module
+            omap44xx_cm2_l4per_i2c2_clkctrl_modulemode_wrf(&cm2,
+                    omap44xx_cm2_modmode_swenabled);
+            // wait for module to get into functional state
+            while(omap44xx_cm2_l4per_i2c2_clkctrl_idlest_rdf(&cm2)
+                    !=omap44xx_cm2_idlest_functional);
+            break;
+        case 3:
+            // enable i2c module
+            omap44xx_cm2_l4per_i2c3_clkctrl_modulemode_wrf(&cm2,
+                    omap44xx_cm2_modmode_swenabled);
+            // wait for module to get into functional state
+            while(omap44xx_cm2_l4per_i2c3_clkctrl_idlest_rdf(&cm2)
+                    !=omap44xx_cm2_idlest_functional);
+            break;
+        case 4:
+            // enable i2c module
+            omap44xx_cm2_l4per_i2c4_clkctrl_modulemode_wrf(&cm2,
+                    omap44xx_cm2_modmode_swenabled);
+            // wait for module to get into functional state
+            while(omap44xx_cm2_l4per_i2c4_clkctrl_idlest_rdf(&cm2)
+                    !=omap44xx_cm2_idlest_functional);
+            break;
+        default:
+            printk(LOG_WARN, "don't know how to enable clocks for I2C%d\n", i2c_index);
+            break;
+    }
+}
+
+void cm2_init(void)
+{
+    mackerel_addr_t cm2_vaddr = omap_dev_map(CM2_PADDR);
+    mackerel_addr_t cm2_clkgen_vaddr = omap_dev_map(CM2_CLKGEN_PADDR);
+    mackerel_addr_t cm2_l4per_vaddr = omap_dev_map(CM2_L4PER_PADDR);
+
+    omap44xx_cm2_initialize(&cm2, cm2_vaddr, cm2_clkgen_vaddr, cm2_l4per_vaddr);
+    
+}
+
+int cm2_get_hsmmc1_base_clock(void)
+{
+    return omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_CLKSEL_rdf(&cm2) == 0x0 ?
+        64000000 : 96000000;
+}
+
+/*
+ * \brief Print CM2 registers
+ */
+void print_cm2(void)
+{
+    char buf[1024];
+    omap44xx_cm2_pr(buf, 1024-1, &cm2);
+
+    printf("%s\n", buf);
+}
+
+void cm2_print_standby_state(void)
+{
+    if (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_STBYST_rdf(&cm2)==0x0) {
+        printf("cm2: mmc1 is functional (not in standby state)\n");
+    } else if (omap44xx_cm2_CM_L3INIT_HSMMC1_CLKCTRL_STBYST_rdf(&cm2)==0x0) {
+        printf("cm2: mmc1 is in stand-by state\n");
+    } else {
+        panic("Undefined standby state for MMC1");
+    }
+}
+
diff --git a/usr/drivers/omap44xx/mmchs/ctrlmod.c b/usr/drivers/omap44xx/mmchs/ctrlmod.c
new file mode 100644 (file)
index 0000000..b5a2e6b
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+
+#include <arm_hal.h>
+#include <gic.h>
+
+#include <omap44xx_ctrlmod.h>
+
+#define SYSCTRL_GENERAL_CORE 0x4a002000u
+#define SYSCTRL_GENERAL_WKUP 0x4a30c000u
+#define SYSCTRL_PADCONF_CORE 0x4a100000u
+#define SYSCTRL_PADCONF_WKUP 0x4a31e000u
+
+static omap44xx_ctrlmod_t ctrlmod;
+
+/*
+ * \brief Initialization of control module
+ */
+void ctrlmod_init(void)
+{
+    lvaddr_t vaddr[4];
+
+    // 4K each, the regions are page aligned
+    lpaddr_t addr[4] = {
+        SYSCTRL_GENERAL_CORE,
+        SYSCTRL_GENERAL_WKUP,
+        SYSCTRL_PADCONF_CORE,
+        SYSCTRL_PADCONF_WKUP
+    };
+
+    // Map
+    for (int i=0; i<4; i++) {
+        vaddr[i] = paging_map_device(addr[i], ARM_L1_SECTION_BYTES);
+        vaddr[i]  += (addr[i] & ARM_L1_SECTION_MASK);
+    }
+
+    // Initialize Mackerel
+    omap44xx_ctrlmod_initialize(&ctrlmod,
+                                (mackerel_addr_t) vaddr[0], 
+                                (mackerel_addr_t) vaddr[1], 
+                                (mackerel_addr_t) vaddr[2], 
+                                (mackerel_addr_t) vaddr[3]);
+}
+
+static bool pbias_got_irq = false;
+/*
+ * We need to configure the extended-drain I/O pads to the right voltage and
+ * turn on the external power supply (TWL6030 on the pandaboard)
+ */
+void sdmmc1_enable_power(void)
+{
+    // compare with Table 18-109 in OMAP TRM, p3681
+    // Step 1: software must keep PWRDNZ low when setting up voltages
+    printk(LOG_NOTE, "%s: Step 1\n", __FUNCTION__);
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_PWRDNZ_wrf(&ctrlmod, 0x0);
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PWRDNZ_wrf(&ctrlmod, 0x0);
+
+    // Step 2: preliminary settings for MMC1_PBIAS and MMC1 I/O cell
+    printk(LOG_NOTE, "%s: Step 2\n", __FUNCTION__);
+    //  1. turn of hiz mode
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_HIZ_MODE_wrf(&ctrlmod, 0x0);
+    //  2. setup PBIAS_IRQ (MA_IRQ_75)
+    gic_enable_interrupt(PBIAS_IRQ,
+                         GIC_IRQ_CPU_TRG_BSP,
+                         0,//                         PIC_IRQ_PRIO_LOWEST,
+                         GIC_IRQ_LEVEL_SENSITIVE,
+                         GIC_IRQ_1_TO_N);
+    //  3. pad multiplexing -- looks ok when dumping pad registers, so I'm
+    //  not doing anything right now -SG
+    //  4. set MMC1 speed control to 26MHz@30pF (0x0) -- alternative 65MHz@30pF (0x1)
+    omap44xx_ctrlmod_CONTROL_MMC1_SDMMC1_SPEEDCTRL_wrf(&ctrlmod,
+            omap44xx_ctrlmod_mmc1_spd_slow);
+    //  5. set MMC1 pullup strength to 10-50kOhm (0x1) -- alt. 50-110kOhm (0x0)
+    omap44xx_ctrlmod_CONTROL_MMC1_SDMMC1_PUSTRENGTH_wrf(&ctrlmod,
+            omap44xx_ctrlmod_mmc1_pstr_weak);
+
+    // Step 3: Program desired SDMMC1_VDDS for MMC I/O in I2C attached power
+    // controller TODO? -- assuming 3.0V for now, manual says reset value is
+    // 3.0V -SG
+
+    // Step 4: Set VMODE bit according to Step 3 (0x1 == 3.0V)
+    printk(LOG_NOTE, "%s: Step 4\n", __FUNCTION__);
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_VMODE_wrf(&ctrlmod, omap44xx_ctrlmod_vlt_hi);
+
+    // Step 5: wait for SDMMC1_VDDS voltage to stabilize TODO
+    // might already be stable after reset? -SG
+
+    // Step 6: Disable PWRDNZ mode for MMC1_PBIAS and MMC1 I/O cell
+    printk(LOG_NOTE, "%s: Step 6\n", __FUNCTION__);
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_PWRDNZ_wrf(&ctrlmod, 0x1);
+    omap44xx_ctrlmod_PBIASLITE_MMC1_PWRDNZ_wrf(&ctrlmod, 0x1);
+
+    // Step 7: Store SUPPLY_HI_OUT bit
+    uint8_t supply_hi_out = 
+        omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_SUPPLY_HI_OUT_rdf(&ctrlmod);
+    printk(LOG_NOTE, "%s: Step 7: supply_hi_out = %d\n", __FUNCTION__, supply_hi_out);
+    printk(LOG_NOTE, "%s: Step 7: vmode_error = %d\n", __FUNCTION__,
+            omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_VMODE_ERROR_rdf(&ctrlmod));
+
+    // Wait for Interrupt
+    while(!pbias_got_irq) { }
+
+    printk(LOG_NOTE, "%s: Step 8\n", __FUNCTION__);
+
+    // Step 8: check VMODE_ERROR and set PWRDNZ if error
+    if (omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_VMODE_ERROR_rdf(&ctrlmod)) {
+        printk(LOG_NOTE, "got VMODE error\n");
+        omap44xx_ctrlmod_PBIASLITE_MMC1_PWRDNZ_wrf(&ctrlmod, 0x0);
+        omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_PWRDNZ_wrf(&ctrlmod, 0x0);
+    }
+    
+    // Step 9: check if SUPPLY_HI_OUT corresponds to SDMMC1_VDDS (3.0V)
+    if (supply_hi_out != omap44xx_ctrlmod_vlt_hi) {
+        printk(LOG_NOTE, "SDMMC1_VDDS seems to be != 3.0V\n");
+        // TODO: redo setting SDMMC1_VDDS
+    } else {
+        // supply_hi_out should be 0x1 (3.0V)
+        assert(supply_hi_out == omap44xx_ctrlmod_vlt_hi);
+        // set VMODE bit to supply_hi_out
+        omap44xx_ctrlmod_PBIASLITE_MMC1_PBIASLITE_VMODE_wrf(&ctrlmod, supply_hi_out);
+    }
+
+    // Step 12: clear PBIAS IRQ
+    gic_ack_irq(PBIAS_IRQ);
+    pbias_got_irq = 0;
+}
+
+void pbias_handle_irq(void)
+{
+    printk(LOG_NOTE, "got pbias interrupt");
+
+    // set got-irq flag
+    
+    pbias_got_irq = true;
+
+    // Activate interrupts again .. 
+    __asm volatile ("CPSIE aif");
+}
+
diff --git a/usr/drivers/omap44xx/mmchs/i2c.c b/usr/drivers/omap44xx/mmchs/i2c.c
new file mode 100644 (file)
index 0000000..86ea4e9
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+
+#include <arm_hal.h>
+
+#include <omap44xx_cm2.h> // for turning on I2C clocks
+#include <ti_i2c.h>
+#include <ti_i2c_dev.h>
+
+// there are 4 GP i2c controllers on the pandaboard
+#define I2C_COUNT 4
+static ti_i2c_t i2c[I2C_COUNT];
+static bool i2c_initialized[I2C_COUNT];
+
+static lpaddr_t i2c_pbase[I2C_COUNT] = 
+{
+    0x48070000u,
+    0x48072000u,
+    0x48060000u,
+    0x48350000u,
+};
+
+// default timeout for waits in ticks
+#define DEFAULT_TIMEOUT (tsc_get_hz() / 4)
+
+#if 0
+#define PBS (64*1024)
+static char PRBUF[PBS];
+#define PRBUFL PRBUF, (PBS-1)
+#endif
+
+/*
+ * \brief initialize I2C controller `i`.
+ */
+void ti_i2c_init(int i) {
+    // map & initialize mackerel device
+    mackerel_addr_t i2c_vbase = omap_dev_map(i2c_pbase[i]);
+    ti_i2c_initialize(&i2c[i], i2c_vbase);
+
+    ti_i2c_t *dev = &i2c[i];
+
+    // turn on clocks
+    cm2_enable_i2c(i);
+
+    // TODO?: enable interrupts
+
+    // Disable i2c controller
+    ti_i2c_con_wr(dev, 0x0000);
+
+    // Issue soft reset
+    ti_i2c_sysc_srst_wrf(dev, 0x1);
+
+    // re-enable & check for reset done
+    ti_i2c_con_en_wrf(dev, 0x1);
+
+    while (ti_i2c_syss_rdone_rdf(dev) == 0x0) {
+        // wait for reset done
+    }
+
+    // disable i2c controller again
+    ti_i2c_con_wr(dev, 0x0);
+
+    // Program prescaler to obtain ~12MHz internal clock
+    // depends on the functional clock, I2Ci_FCLK is 96MHz, so the best
+    // prescaler value is 0x7 as the divider is taken +1 (so setting 7
+    // results in dividing by 8).
+    ti_i2c_psc_wr(dev, 0x7);
+
+    // set bitrate to 100kbps -- values taken from freebsd
+    ti_i2c_scll_scl_wrf(dev, 0xd);
+    ti_i2c_sclh_scl_wrf(dev, 0xf);
+
+    // optional: configure HS mode
+
+    // configure own address
+    // according to freebsd this is not necessary in single master mode -SG
+
+    // set rx & tx threshold -- set to 5 (register value + 1)
+    ti_i2c_buf_txtrsh_wrf(dev, 0x4);
+    ti_i2c_buf_rxtrsh_wrf(dev, 0x4);
+
+    // bring controller out of reset
+    //  Fast/Standard mode
+    ti_i2c_con_opmode_wrf(dev, ti_i2c_opmode_fs);
+    //  Enable
+    ti_i2c_con_en_wrf(dev, 0x1);
+
+    // Initialize the controller
+
+    // configure master mode
+    ti_i2c_con_mst_wrf(dev, 0x1);
+
+    // enable interrupts for receive and transmit data ready
+    ti_i2c_irqenable_clr_wr(dev, 0xffff);
+    ti_i2c_irqenable_set_xrdy_ie_wrf(dev, 0x1);
+    ti_i2c_irqenable_set_rrdy_ie_wrf(dev, 0x1);
+
+    // enable DMA
+    // we're not using DMA for now... -SG
+
+    // set initialized flag
+    i2c_initialized[i] = true;
+
+    return;
+}
+
+static inline bool ti_i2c_poll_stat(ti_i2c_t *dev, ti_i2c_irqstatus_t flags,
+        ti_i2c_irqstatus_t *retflags, int32_t timeout)
+{
+    // poll until timeout
+    uint32_t start_ticks = tsc_read();
+    uint32_t ticks;
+    int32_t waittime = timeout;
+
+    while (waittime > 0) {
+        ti_i2c_irqstatus_t stat = ti_i2c_stat_rd(dev);
+        if (stat & flags) {
+            if (retflags) {
+                *retflags = stat;
+            }
+            return true;
+        }
+        ticks = tsc_read();
+        waittime -= (ticks - start_ticks);
+        start_ticks = ticks;
+    }
+    return false;
+}
+
+static bool ti_i2c_wait_for_free_bus(ti_i2c_t *dev, int32_t timeout)
+{
+    // check if bus-busy == 0 --> bus free
+    if (ti_i2c_stat_bb_rdf(dev) == 0) {
+        return true;
+    }
+
+    // poll while bus busy or until timeout
+    return ti_i2c_poll_stat(dev, ti_i2c_irq_flag_bb, NULL, timeout);
+}
+
+static errval_t
+ti_i2c_read(ti_i2c_t *dev, uint8_t *buf, uint16_t length)
+{
+    bool wfb;
+    wfb = ti_i2c_wait_for_free_bus(dev, DEFAULT_TIMEOUT);
+    if (!wfb) {
+        printk(LOG_ERR, "wait for bus free timed out\n");
+        return SYS_ERR_I2C_WAIT_FOR_BUS;
+    }
+
+    // TODO: interrupt-driven?
+
+    // write number of bytes to read
+    ti_i2c_cnt_wr(dev, length);
+
+    // clear write bit & initiate the read transaction, setting
+    // the start bit (STT) starts the transaction
+    ti_i2c_con_t con = ti_i2c_con_rd(dev);
+    con = ti_i2c_con_trx_insert(con, 0);
+    con = ti_i2c_con_mst_insert(con, 1);
+    con = ti_i2c_con_stp_insert(con, 1);
+    con = ti_i2c_con_stt_insert(con, 1);
+    ti_i2c_con_wr(dev, con);
+
+    ti_i2c_irqstatus_t events, retevents;
+
+    events = ti_i2c_irq_flag_al // arbitration lost
+           | ti_i2c_irq_flag_nack // no acknowledgement
+           | ti_i2c_irq_flag_ardy // register access ready
+           | ti_i2c_irq_flag_rdr // receive draining
+           | ti_i2c_irq_flag_rrdy; // receive ready
+
+    uint16_t amount = 0, sofar = 0;
+    errval_t err = SYS_ERR_OK;
+    // reading loop
+    while (true) {
+        // poll for NACK, AL, ARDY, RDR and RRDY
+        while(!ti_i2c_poll_stat(dev, events, &retevents, DEFAULT_TIMEOUT)) {
+            // poll for receive ready
+        }
+
+        if (retevents & ti_i2c_irq_flag_al) {
+            printk(LOG_WARN, "arbitration lost\n");
+            err = SYS_ERR_I2C_FAILURE;
+            break;
+        }
+
+        if (retevents & ti_i2c_irq_flag_nack) {
+            printk(LOG_WARN, "no ACK from slave\n");
+            err = SYS_ERR_I2C_FAILURE;
+            break;
+        }
+
+        // check if we have finished
+        if (retevents & ti_i2c_irq_flag_ardy) {
+            // register access ready --> transaction complete
+            printk(LOG_NOTE, "ARDY transaction complete\n");
+            err = SYS_ERR_OK;
+            break;
+        }
+
+        // read some data
+        if (retevents & ti_i2c_irq_flag_rdr) {
+            // Receive draining interrupt --> we got the last data bytes
+            printk(LOG_NOTE, "Receive draining interrupt\n");
+
+            /* get the number of bytes in the FIFO */
+            amount = ti_i2c_bufstat_rxstat_rdf(dev);
+        }
+        else if (retevents & ti_i2c_irq_flag_rrdy) {
+            // Receive data ready interrupt --> got data
+            printk(LOG_NOTE, "Receive data ready interrupt\n");
+
+            // get the number of bytes in the FIFO
+            amount = ti_i2c_bufstat_rxstat_rdf(dev);
+            amount += 1;
+        }
+
+        // sanity check we haven't overwritten the array
+        if ((sofar + amount) > length) {
+            printk(LOG_WARN, "to many bytes to read\n");
+            amount = (length - sofar);
+        }
+
+        // read the bytes from the fifo
+        for (int i = 0; i < amount; i++) {
+            buf[sofar++] = (uint8_t)ti_i2c_data_data_rdf(dev);
+        }
+
+        // attempt to clear the receive ready bits
+        ti_i2c_stat_rdr_wrf(dev, 1);
+        ti_i2c_stat_rrdy_wrf(dev, 1);
+    }
+
+    return err;
+}
+
+static errval_t
+ti_i2c_write(ti_i2c_t *dev, uint8_t *buf, uint16_t length)
+{
+    bool wfb;
+    wfb = ti_i2c_wait_for_free_bus(dev, DEFAULT_TIMEOUT);
+    if (!wfb) {
+        printk(LOG_ERR, "wait for bus free timed out\n");
+        return SYS_ERR_I2C_WAIT_FOR_BUS;
+    }
+
+    // TODO: interrupt-driven?
+
+    // write number of bytes to write
+    ti_i2c_cnt_wr(dev, length);
+
+    // set write bit & initiate the write transaction, setting
+    // the start bit (STT) starts the transaction
+    ti_i2c_con_t con = ti_i2c_con_rd(dev);
+    con = ti_i2c_con_trx_insert(con, 1);
+    con = ti_i2c_con_mst_insert(con, 1);
+    con = ti_i2c_con_stp_insert(con, 1);
+    con = ti_i2c_con_stt_insert(con, 1);
+    ti_i2c_con_wr(dev, con);
+
+    ti_i2c_irqstatus_t events, retevents;
+    events = ti_i2c_irq_flag_al // arbitration lost
+           | ti_i2c_irq_flag_nack // no acknowledgement
+           | ti_i2c_irq_flag_ardy // register access ready
+           | ti_i2c_irq_flag_xdr // transmit draining
+           | ti_i2c_irq_flag_xrdy; // transmit ready
+
+    uint16_t amount = 0, sofar = 0;
+    errval_t err = SYS_ERR_OK;
+
+    // writing loop
+    while (true) {
+        // poll for NACK, AL, ARDY, XDR and XRDY
+        while(!ti_i2c_poll_stat(dev, events, &retevents, DEFAULT_TIMEOUT)) {
+            // poll for events
+        }
+
+        if (retevents & ti_i2c_irq_flag_al) {
+            printk(LOG_WARN, "arbitration lost\n");
+            err = SYS_ERR_I2C_FAILURE;
+            break;
+        }
+
+        if (retevents & ti_i2c_irq_flag_nack) {
+            printk(LOG_WARN, "no ACK from slave\n");
+            err = SYS_ERR_I2C_FAILURE;
+            break;
+        }
+
+        // check if we have finished
+        if (retevents & ti_i2c_irq_flag_ardy) {
+            // register access ready --> transaction complete
+            printk(LOG_NOTE, "ARDY transaction complete\n");
+            err = SYS_ERR_OK;
+            break;
+        }
+
+        // send some data
+        if (retevents & ti_i2c_irq_flag_xdr) {
+            // transmit draining interrupt --> we are sending the last data bytes
+            printk(LOG_NOTE, "Receive draining interrupt\n");
+
+            /* get the number of bytes that fit in the FIFO */
+            amount = ti_i2c_bufstat_txstat_rdf(dev);
+        }
+        else if (retevents & ti_i2c_irq_flag_xrdy) {
+            // transmit data ready interrupt --> can send data
+            printk(LOG_NOTE, "Receive data ready interrupt\n");
+
+            // get the number of bytes that fit in the FIFO
+            amount = ti_i2c_bufstat_txstat_rdf(dev);
+            amount += 1;
+        }
+
+        // sanity check so we don't write more bytes than available
+        if ((sofar + amount) > length) {
+            printk(LOG_WARN, "truncating length to not access data beyond buf\n");
+            amount = (length - sofar);
+        }
+
+        // write the bytes to the fifo
+        for (int i = 0; i < amount; i++) {
+            ti_i2c_data_data_wrf(dev, buf[sofar++]);
+        }
+
+        // attempt to clear the receive ready bits
+        ti_i2c_stat_xdr_wrf(dev, 1);
+        ti_i2c_stat_xrdy_wrf(dev, 1);
+    }
+
+    // reset registers
+    con = ti_i2c_con_default;
+    con = ti_i2c_con_en_insert(con, 0x1);
+    con = ti_i2c_con_mst_insert(con, 0x1);
+    con = ti_i2c_con_stp_insert(con, 0x1);
+    ti_i2c_con_wr(dev, con);
+
+    return err;
+}
+
+
+/*
+ * \brief Transfer (multiple) messages over I2C bus `i`
+ */
+errval_t ti_i2c_transfer(int devid, struct i2c_msg *msgs, size_t msgcount)
+{
+    if (!i2c_initialized[devid]) {
+        return SYS_ERR_I2C_UNINITIALIZED;
+    }
+    ti_i2c_t *dev = &i2c[devid];
+    uint16_t len;
+    uint8_t *buf;
+
+    for (int i = 0; i < msgcount; i++) {
+        len = msgs[i].length;
+        buf = msgs[i].buf;
+
+        // zero length transfers are not allowed
+        if (len == 0 || buf == NULL) {
+            return SYS_ERR_I2C_ZERO_LENGTH_MSG;
+        }
+
+        // set slave address
+        ti_i2c_sa_sa_wrf(dev, msgs[i].slave);
+
+        // perform read or write
+        if (msgs[i].flags & I2C_RD) {
+            ti_i2c_read(dev, buf, len);
+        } else {
+            ti_i2c_write(dev, buf, len);
+        }
+    }
+
+    return SYS_ERR_OK;
+}
+
diff --git a/usr/drivers/omap44xx/mmchs/mmchs.c b/usr/drivers/omap44xx/mmchs/mmchs.c
new file mode 100644 (file)
index 0000000..fe4e6e9
--- /dev/null
@@ -0,0 +1,1006 @@
+ /*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+
+#include <arm_hal.h>
+
+#include <omap44xx_mmchs.h>
+#include <omap44xx_cm2.h>
+#include <omap44xx_ctrlmod.h>
+
+#include <dev/omap/omap44xx_mmchs_dev.h>
+#include <dev/sdhc_dev.h>
+
+#include <gic.h>
+
+static sdhc_t sdhc;
+static omap44xx_mmchs_t mmchs;
+
+// XXX Temporarily disable annoying warnings about unused functions!!
+#pragma GCC diagnostic ignored "-Wunused-function" 
+#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"
+
+#define PBS (64*1024)
+static char PRBUF[PBS];
+#define PRBUFL PRBUF, (PBS-1)
+
+/*
+ * \brief Set divider for frequency configuration
+ */
+static void mmchs_set_frequency(int freq_div)
+{
+    int base_clock;
+    base_clock = cm2_get_hsmmc1_base_clock();
+
+    printf("mmchs: setting clock frequency to %d Hz\n",
+           (base_clock/freq_div));
+    sdhc_sysctl_clkd_wrf(&sdhc, freq_div);
+
+}
+
+/*
+ * \brief Do a software reset of the MMC module
+ *
+ * Reset is only done if resetdone flag is not 1 already .. 
+ *
+ * Otherwise there is a risk that we cannot detect when the second reset
+ * is acutally completed (since the flag is 1 alread) which might make us
+ * loose some of the future actions on the MMC since it is not ready.
+ *
+ * After powering up the PandaBoard, RESETDONE usually is 1 already 
+ *
+ * Figure 24-36 
+ */
+static void mmchs_do_sw_reset(void)
+{
+    printf("mmchs: do_sw_reset()\n");
+    omap44xx_mmchs_SYSSTATUS_pr(PRBUFL,&mmchs);
+    printf("mmchs:  %s", PRBUF);
+    omap44xx_mmchs_HL_SYSCONFIG_SOFTRESET_wrf(&mmchs, 0x1);
+
+    volatile uint32_t l;
+    for(l = 0; omap44xx_mmchs_HL_SYSCONFIG_SOFTRESET_rdf(&mmchs) == 1; l++);
+    printf("mmchs:  waited %d loops for HL_SYSCONFIG_SOFTRESET\n", l);
+    for(l = 0; omap44xx_mmchs_SYSCONFIG_SOFTRESET_rdf(&mmchs) == 1; l++);
+    printf("mmchs:  waited %d loops for SYSCONFIG_SOFTRESET\n", l);
+    for(l = 0; omap44xx_mmchs_SYSSTATUS_RESETDONE_rdf(&mmchs) == 0; l++);
+    printf("mmchs:  waited %d loops for SYSSTATUS_RESETDONE\n", l);
+}
+
+
+/*
+ * \brief Reset command and data state machine
+ *
+ * See BSD code ti_mmchs.c line 1357
+ */
+static void mmchs_do_state_machine_reset(void)
+{
+    volatile uint32_t l;
+    printf("mmchs: do_state_machine_reset()\n");
+
+    sdhc_sysctl_sra_wrf(&sdhc, 0x1);
+    for(l = 0; sdhc_sysctl_sra_rdf(&sdhc) != 0; l++);
+    printf("mmchs:  waited %d loops for sysctl_sra\n", l);
+}
+
+
+/*
+ * \brief Print MMCHS registers
+ */
+static void print_mmchs(void)
+{
+    omap44xx_mmchs_pr(PRBUFL, &mmchs);
+    printf("%s\n", PRBUF);
+    sdhc_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+}
+
+/*
+ * \brief Print MMC error state
+ */
+static void print_mmchs_state(void)
+{
+    sdhc_stat_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+
+    sdhc_ps_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+
+}
+
+volatile uint32_t dummy = 0;
+
+/*
+ * \brief Sleep for @msec miliseconds
+ *
+ * XXX I am sure there is a better way to do this ..
+ */
+static void mmchs_wait_msec(long msec)
+{
+    int i=0, sum = 0; 
+    long end = (1200000*msec/8);
+
+    // Cannot use volatile variables in loop
+    while (++i<end)  {
+        sum+=i+end;
+    }
+
+    dummy += sum;
+}
+
+/*
+ * \brief Do CMD line reset
+ *
+ * TRM 24.5.1.2.1.2, page 5120
+ */
+static void mmchs_cmd_line_reset(void)
+{
+    sdhc_sysctl_src_wrf(&sdhc, 0x1);
+    while (sdhc_sysctl_src_rdf(&sdhc)!=0x1)
+        ;
+    while (sdhc_sysctl_src_rdf(&sdhc)!=0x0)
+        ;
+}
+
+/*
+ * \brief Initialize and identify
+ *
+ * This is according to SD card spec v3, chp 3.6
+ */
+int mmchs_init_and_ident_card(void)
+{
+    // Reset card
+    // XXX Keep pin 1 high during execution??
+    printf("identify: cmd0\n");
+    mmchs_send_cmd(0, 0);
+
+    mmchs_wait_msec(1000);
+
+    // Free BSD: mmc_send_if_conf [mmc.c]
+    // Sets vhs, and uses 0xAA as pattern
+    uint32_t cmd8arg = 0;
+    sdhc_cmd8_t cp= (sdhc_cmd8_t)&cmd8arg;
+    // 2.7-3.6V (seems to  be the only value allowed .. )
+    sdhc_cmd8_vhs_insert(cp, 0x1);
+    // Recommended pattern is: 0x1010101010
+    sdhc_cmd8_pattern_insert(cp, 0xaa);
+    printf("identify: cmd8\n");
+    mmchs_send_cmd(8, cmd8arg);
+
+    // Wait for result
+    return mmchs_finalize_cmd();
+}
+
+/*
+ * \brief TBD
+ *
+ * see TRM Figure 24-38 left-handed
+ * and BSD code in ti_mmchs_send_init_stream in ti_mmchs.c
+ *
+ * Free BSD has a slightly different approach compared to the
+ * TRM. They issue CMD0 commands and wait for the STAT_CC bit to be
+ * set, whereas the TRM just waits for 1 ms.
+ *
+ * Precondition: Module initiliaztion
+ */
+static void mmchs_init_stream(void)
+{
+    printf("mmchs: initializing stream .. \n");
+
+    // Make sure that the command line is not busy at this point 
+    assert (sdhc_ps_cmdi_rdf(&sdhc)==0x0);
+
+    // Save original IE and ISE registers
+    sdhc_ir_t ie = sdhc_ie_rd(&sdhc);
+    sdhc_ir_t ise = sdhc_ise_rd(&sdhc);
+
+    // Enable interrupts, so that CC will be set
+    // These are SD card interrupts.
+    // If we don't do that, STAT_CC will not be set
+    // BSD line 894
+    // XXX Don't use constant here .. 
+    sdhc_ie_wr(&sdhc, 0x307F0033);
+
+    // Disable genernation of status events
+    sdhc_ise_wr(&sdhc, 0x0);
+
+    // Initialize stream
+    omap44xx_mmchs_CON_INIT_wrf(&mmchs, 0x1); 
+    // Writing a dummy command
+    // CMD0 seems to be a reset command ..
+    sdhc_ctm_rawwr(&sdhc, 0x0);
+    // Wait for completion of command
+    while (sdhc_stat_cc_rdf(&sdhc)!=0x1) ;
+    mmchs_wait_msec(1);
+    // Clear status field, so that we see when CC (command complete) sticks
+    sdhc_stat_cc_wrf(&sdhc, 0x1);
+
+    // Need to do the whole procedure twice, since we cannot
+    // make our clock slow enough to not have more  than 80 cycles 
+    // in one msec .. 
+
+    // End initialization sequence ...
+    omap44xx_mmchs_CON_INIT_wrf(&mmchs, 0x0);
+
+    printf("mmchs: stream init done (how do we know it works?)\n");
+
+    // Reset the interrupt configuration
+    sdhc_ie_wr(&sdhc, ie);
+    sdhc_ise_wr(&sdhc, ise);
+
+    // Unset STAT 
+    sdhc_stat_rawwr(&sdhc, ~0x0);
+    /* sdhc_stat_rd(&sdhc); // << why are we reading this (from BSD) */
+
+    // Change clock frequency to fit protocol?
+    // TRM 24.5.1.2.1.7.2
+    /* mmchs_change_clock_frequency(); */
+
+    mmchs_cmd_line_reset();
+
+    // Make sure nothing went wrong in init
+    /* assert(sdhc_stat_bada_rdf(&sdhc)==0x0); */
+    /* assert(sdhc_stat_erri_rdf(&sdhc)==0x0); */
+}
+
+/* 
+ * \brief Identify card
+ *
+ * Does currently not work! Report all card types being present, 
+ * no matter what and if any card is actually inserted!
+ *
+ * This is according to TI TRM
+ */
+void mmchs_identify_card(void)
+{
+    // << OMAP TRM method does not work!
+
+    // send a CMD0 command
+    // TRM 24.5.1.2.1.7.1
+    mmchs_send_cmd(CMD0, 0);
+
+    // send a CMD5 command
+    // XXX don't use the wrapper function    mmchs_send_cmd(CMD5);
+
+    // Wait for CMD line to become available
+    while (sdhc_ps_cmdi_rdf(&sdhc)!=0);
+    // Unset STAT bits. These bits will reflect completion of command execution
+    sdhc_stat_wr(&sdhc, ~0x0);
+    assert (sdhc_stat_cc_rdf(&sdhc)==0x0);
+    // Issue the command
+    sdhc_ctm_index_wrf(&sdhc, 0x5);
+
+    // XXX Does this detect if there is actually a card in the slot or just
+    //     if the controller has the capability to read a card of that type?
+    uint32_t cc, cto, run = 0;
+
+    // Wait for completion
+    do {
+        cc = sdhc_stat_cc_rdf(&sdhc); 
+        cto = sdhc_stat_cto_rdf(&sdhc); 
+        run = 0;
+
+        if (cc==0x1) {
+            printf("SDIO card detected .. printing registers ..\n");
+            assert (sdhc_stat_bada_rdf(&sdhc)==0x0);
+        } else if (cto==0x1) {
+            printf("No SDIO card detected .. \n");
+        } else {
+            run = 1;
+        }
+    } while(run);
+
+    assert(sdhc_stat_bada_rdf(&sdhc)==0x0);
+
+    // CMD line reset
+    mmchs_cmd_line_reset();
+
+    // Send a CMD8 command
+    // CC value?          0x1 -> SD card
+    // CMD8 needs an argument ..
+    mmchs_send_cmd(CMD8, 0);
+    do {
+        if (sdhc_stat_cc_rdf(&sdhc)) {
+            printf("SD card found .. (v 2.0 or higher)\n");        
+            return;
+        } else {
+            printf("No SD card found .. \n");
+        }
+    } while (sdhc_stat_cto_rdf(&sdhc)!=0x1);
+
+    // We do not check for other cards (i.e. SD v1.x, or unknown cards .. )
+    panic("There is no SD v2 card in the slot .. \n");
+}
+
+/*
+ * \brief Change the block frequency
+ *
+ * The maximum operating frequency is 50 MHz [PLS. page 1] 
+ * TRM, Figure 24-48, page 5132
+ * 
+ * \param clkdiv Clockdivider value to use
+ */
+static void mmchs_change_clock_frequency(int clkdiv)
+{
+    // Disable clock
+    sdhc_sysctl_cen_wrf(&sdhc, 0x0);
+
+    // Set the frequency
+    // The base frequency we get from the L3 interconnect is 96 MHz,
+    // we want to be below 50 MHz, so we use 2 as a divider for the clock
+    mmchs_set_frequency(clkdiv);
+
+    // Wait for internal clock to be stable .. 
+    while (!sdhc_sysctl_ics_rdf(&sdhc));
+
+    // Enable SD card clock
+    sdhc_sysctl_cen_wrf(&sdhc, 0x1);
+}
+
+/*
+ * \brief Send a command using polling
+ *
+ * \param cmd_idx Index of the command to issue (e.g. 0 for CMD0)
+ * \param arg Argument of the command, will be written to the ARG register.
+ *    These are given as bits [8:39] in the Physical Layer spec (see page 25)
+ *
+ * TRM Figure 24-46, page 5129
+ * HCS      3.7.1.1, page 107
+ *          3.7.1.2, page 109
+ *
+ */
+void mmchs_send_cmd(int cmd_idx, uint32_t arg)
+{
+    // Wait for previous command to finish
+    int loop = 0;
+    while (sdhc_ps_cmdi_rdf(&sdhc)!=0x0/*  ||  */
+           /* sdhc_ps_DATI_rdf(&mmchs)!=0x0 */) { // HCS, 2.2.6
+        // but DATI not mentioned in HCS 3.7.1.2
+        // okay, depends on busy signal. Don't need to check if the busy signal is used
+
+        mmchs_wait_msec(1);
+
+        if(++loop>10000) {
+
+            print_mmchs();
+            panic("mmchs_send_cmd failed, CMDI seems to stick .. ");
+        }
+    }
+
+    // FreeBSD: ti_mmchs.c, line 589
+    // These values are only valid for MMC cards
+    omap44xx_mmchs_CON_t con = omap44xx_mmchs_CON_rd(&mmchs);
+    con = omap44xx_mmchs_CON_MIT_insert(con, 0x0);
+    con = omap44xx_mmchs_CON_STR_insert(con, 0x0);
+    // Written later .. 
+
+    // XXX Set CSRE if response type permits
+    //     see standard spec
+    // This seems to be to detect some kind of card error
+    // Don't think we need this, FreeBSD does not use it either
+
+    // Write MMCHS_SYSCTL . DTO
+    // DTO is the data timout counter
+    // XXX CAPA_TCP is 0, does this mean that the timeout counter will not work?
+    /* printf("Timeout counter base frequency: %d\n", sdhc_capa_TCF_rdf(&mmchs)); */
+    /* printf("Timeout value is: %d\n", sdhc_sysctl_dto_rdf(&sdhc)); */
+    sdhc_sysctl_dto_wrf(&sdhc, 0xe);
+
+    // XXX Interrupt configuration
+    //     Setting MMCHS_IE
+    //     and MMCHS_ISE
+    //     to enable interrupts
+    /* sdhc_ie_wr(&sdhc, ~0x0); */
+    /* sdhc_ise_wr(&sdhc, 0x0); */
+    sdhc_ir_t ise = sdhc_ir_default;
+    ise = sdhc_ir_cerr_insert(ise, 0x1);
+    ise = sdhc_ir_cto_insert(ise, 0x1); 
+    ise = sdhc_ir_cc_insert(ise, 0x1);
+    ise = sdhc_ir_ceb_insert(ise, 0x1);
+    // Written later .. 
+
+    // Unset all bits in STAT
+    sdhc_stat_wr(&sdhc, ~0x0);
+
+    sdhc_ctm_t cmd = sdhc_ctm_default;
+
+    // Configure command
+    // For cmd8, which expects R7, .. 
+    cmd = sdhc_ctm_index_insert(cmd, cmd_idx); // Command ID
+    switch (cmd_idx) {
+    case CMD8:
+        // Free BSD: mmc_send_if_conf [mmc.c]
+        // RSP_TYPE follows from MMC_CMD_BCR
+        cmd = sdhc_ctm_rsp_type_insert(cmd, 0x2); // R7
+        // MMC_RSP_R7 = MMC_RSP_PRESENT | MMC_RSP_CRC
+        cmd = sdhc_ctm_dp_insert(cmd, 0x1); // Data present
+        // Do a CRC check
+        cmd = sdhc_ctm_ccce_insert(cmd, 0x1);
+        ise = sdhc_ir_ccrc_insert(ise, 0x1);
+        // Do index checking
+        ise = sdhc_ir_cie_insert(ise, 0x1);
+        break;
+    case CMD0:
+        cmd = sdhc_ctm_rsp_type_insert(cmd, 0x0); // R7
+        break;
+    default:
+        panic("Unknown command .. ");
+    }
+
+    if (1) { // no data
+        // XXX Write MMCHS_BLK
+        //     Free BSD ti_mmchs.c l 631'ish
+        //     for now, we don't have any data .. 
+        sdhc_blckcnt_wr(&sdhc, 0x0);
+
+        // Write CON
+        omap44xx_mmchs_CON_wr(&mmchs, con);
+
+        // Write IE (to enable internal generation of interrupts)
+        // These are not actual interrupts
+        sdhc_ie_wr(&sdhc, ise);
+        
+        // Write ISE (to enable interrupts passed to the system)
+        // Enabling some interrupts I believe could be useful for debugging
+        ise = sdhc_ir_default;
+        ise = sdhc_ir_bada_insert(ise, 0x1); // Bad access 
+        ise = sdhc_ir_dto_insert(ise, 0x1);  // Data timeout
+        ise = sdhc_ir_cto_insert(ise, 0x1);  // Command timeout
+        ise = sdhc_ir_cerr_insert(ise, 0x1); // Card error
+        ise = sdhc_ir_dcrc_insert(ise, 0x1); // Data CRC error
+        ise = sdhc_ir_ccrc_insert(ise, 0x1); // Command CRC err
+        ise = sdhc_ir_cirq_insert(ise, 0x1); // Command CRC err
+        ise = sdhc_ir_crem_insert(ise, 0x1); // Command CRC err
+        ise = sdhc_ir_cins_insert(ise, 0x1); // Command CRC err
+        sdhc_ise_wr(&sdhc, ise);
+
+        // Write command argument
+       sdhc_arg1_wr(&sdhc, arg);
+        sdhc_ctm_wr(&sdhc, cmd);
+    }
+}
+
+static int mmchs_finalize_cmd(void)
+{
+    volatile int32_t cto;
+    volatile int32_t ccrc;
+    volatile int32_t cc;
+
+    int loop = 1; // << run loop until 0
+    int cnt = 0;
+
+    do {
+        
+        if (++cnt>1000) {
+
+            printf("Timout for command, aborting .. \n");
+            loop = 0;
+            print_mmchs_state();
+        }
+
+        cto = sdhc_stat_cto_rdf(&sdhc); // < Command Timeout Error
+        ccrc = sdhc_stat_ccrc_rdf(&sdhc);
+        cc = sdhc_stat_cc_rdf(&sdhc);
+        
+        if (cto==0x1) { // << Timeout?
+            loop = 0;
+            mmchs_cmd_line_reset();
+            return MMCHS_RESP_TIMEOUT;
+        } else if (cc==0x1) { // << Command complete?
+            sdhc_resp_pr(PRBUFL, &sdhc);
+            sdhc_ctm_pr(PRBUFL, &sdhc);
+            printf("CMD:\n%s\n", PRBUF);
+            loop = 0;
+            // Check for response ..
+            if (sdhc_ctm_rsp_type_rdf(&sdhc)!=0x0) {
+                // Read response
+                printf("mmchs_send_cmd: CC - got a response! "
+                       "Doing a mackerel print .. \n");
+                sdhc_resp_pr(PRBUFL, &sdhc);
+                // Verify error
+                if (sdhc_stat_cie_rdf(&sdhc)!=0x0 ||
+                    sdhc_stat_ceb_rdf(&sdhc)!=0x0 ||
+                    sdhc_stat_ccrc_rdf(&sdhc)!=0x0 ||
+                    sdhc_stat_cerr_rdf(&sdhc)!=0x0) {
+                    
+                    print_mmchs();
+                    print_cm2();
+                    panic("mmchs_send_cmd: error - registers got dumped .. ");
+                }
+            } else {
+                printf("mmchsd_send_cmd: no response \n");
+            }
+        }
+
+        mmchs_wait_msec(1);
+
+    } while(loop);
+        
+    printf("mmchs_send_cmd end (result after %d loop iterations) \n", cnt);
+    return MMCHS_RESP_SUCCESS;
+}
+
+#ifdef MMCHS_DEBUG
+/*
+ * \brief Test register access
+ *
+ * Triest to write a couple of registers and reads them 
+ * again to see if the reads return the changed value.
+ *
+ * I am doing this in a loop because I read somewhere that
+ * the device might be idle and needs to wake up first (which
+ * is triggered by the register access)
+ *
+ * STATE: This works for all but DVAL
+ */
+static void mmchs_test_register_write(void)
+{
+    printf("mmchs_test_register_write\n");
+
+    for(int i=0; i<100; i++) {
+
+        printf("HL standby is: %d - "
+               "HL idle is: %d - "
+               "DVAL is: %d - "
+               "standby is: %d \n", 
+               omap44xx_mmchs_HL_SYSCONFIG_STANDBYMODE_rdf(&mmchs),
+               omap44xx_mmchs_HL_SYSCONFIG_IDLEMODE_rdf(&mmchs),
+               omap44xx_mmchs_CON_DVAL_rdf(&mmchs),
+               omap44xx_mmchs_SYSCONFIG_STANDBYMODE_rdf(&mmchs));
+
+        omap44xx_mmchs_HL_SYSCONFIG_STANDBYMODE_wrf(&mmchs, 0x1);
+        omap44xx_mmchs_HL_SYSCONFIG_IDLEMODE_wrf(&mmchs, 0x1);
+        omap44xx_mmchs_SYSCONFIG_STANDBYMODE_wrf(&mmchs, 0x1);
+        omap44xx_mmchs_CON_DVAL_wrf(&mmchs, 0x1);
+
+        volatile int t = 0;
+        do {
+            t++;
+        } while(t<CYCLES_PER_MSEC/10);
+
+    }
+
+    printf("mmchs_test_register_write .. DONE\n");
+}
+#endif
+
+/*
+ * \brief Print information on the power state of the MMC
+ *
+ * See SD Host Controller Spec, 1.10
+ */
+static void mmchs_print_power_state(void)
+{
+    printf("Internal clock enable: %d\n", sdhc_sysctl_ice_rdf(&sdhc));
+    printf("Card Inserted: %d\n", sdhc_ps_cins_rdf(&sdhc));
+    printf("SD Bus Power: %d\n", sdhc_hctl_sdbp_rdf(&sdhc));
+    printf("SD Clock Enable: %d\n", sdhc_sysctl_cen_rdf(&sdhc));
+    printf("Command Inhibit: %d\n", sdhc_ps_cmdi_rdf(&sdhc));
+    printf("DAT inhibit: %d\n", sdhc_ps_dati_rdf(&sdhc));
+}
+
+/*
+ * \brief Disable standby mode
+ *
+ * Figured this one out by reading descriptions of device regiters ..
+ */
+ static void mmchs_disable_standby(void) 
+{
+    // This is not part of the official initialization flow documentation
+    omap44xx_mmchs_HL_SYSCONFIG_STANDBYMODE_wrf(&mmchs, 0x1);
+    omap44xx_mmchs_HL_SYSCONFIG_IDLEMODE_wrf(&mmchs, 0x1);
+    omap44xx_mmchs_SYSCONFIG_STANDBYMODE_wrf(&mmchs, 0x1);
+}
+
+/*
+ * \brief Enable wakupe of the host controller
+ *
+ * OMAP TRM 24.5.1.1.2.4
+ */
+static void mmchs_enable_wakeup(void)
+{
+    omap44xx_mmchs_SYSCONFIG_ENAWAKEUP_wrf(&mmchs, 0x1);
+    sdhc_hctl_iwe_wrf(&sdhc, 0x1);
+}
+
+/*
+ * \brief Detect if there is a card in the card reader
+ *
+ * SD card spec 3.1
+ * This is not working! Maybe we do need interrupt for that?
+ */
+static void mmchs_detect_card(void)
+{
+    sdhc_stat_wr(&sdhc, ~0x0);
+    assert(sdhc_stat_cirq_rdf(&sdhc)==0x0);
+
+    // Read old interrupt configuration
+    sdhc_ir_t ie = sdhc_ie_rd(&sdhc);
+    sdhc_ir_t ise = sdhc_ise_rd(&sdhc);
+    // Enable detection for insertion of card .. 
+    ie =  sdhc_ir_cins_insert(ie, 0x1);
+    ie =  sdhc_ir_crem_insert(ie, 0x1);
+    ise = sdhc_ir_crem_insert(ise, 0x1);
+    ise = sdhc_ir_cins_insert(ise, 0x1);
+    // Write new interrupt configuration
+    sdhc_ie_wr(&sdhc, ie);
+    sdhc_ise_wr(&sdhc, ise);
+
+    printf("Waiting for card to be inserted .. \n");
+    sdhc_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+
+    sdhc_ise_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+    sdhc_ie_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+
+    /* int i = 0; */
+    /* while (sdhc_ps_cins_rdf(&sdhc)!=0x1) { */
+
+    /*     if (++i>10000) { */
+    /*         printf("No card detected .. \n"); */
+    /*         return; */
+    /*     } */
+
+    /*     mmchs_wait_msec(1); */
+    /* } */
+
+    /* printf("Card detected .. \n"); */
+    /* /\* mmchs_init_stream(); *\/ */
+    /* /\* mmchs_identify_card(); *\/ */
+}
+
+/*
+ * \brief Prepare configuration of MMC host controller
+ *
+ */
+static void mmchs_pre_configure(void) 
+{
+    printf("mmchs: pre_configure()\n");
+
+    // TRM chapter 18: Control module? Is that CM2?
+    sdmmc1_enable_power();
+
+    // ==================================================
+    // STEP 2: Software reset
+    mmchs_do_sw_reset();
+    mmchs_do_state_machine_reset();
+    
+    // ==================================================
+    // Step 1b: Disable idle and stanbdy states
+    mmchs_disable_standby();
+    mmchs_enable_wakeup();
+}
+
+/*
+ * \brief Configure and initialize MMC
+ *
+ * TRM Section 24.5.1.1.2 on page 5114 ff
+ * and BSD code ti_mmchs_hw_init in ti_mmchs.c
+ *
+ */
+static void mmchs_configure(void) 
+{
+    // ==================================================
+    // STEP 3: Set module hardware capabilities
+    // Need to write MMCHS_CAPA[26:24] ..
+    // BSD: ti_mmchs_hw_init, line 1373
+    sdhc_capa_t capa = sdhc_capa_rd(&sdhc);
+    capa = sdhc_capa_vs18_insert(capa, 0x1);
+    capa = sdhc_capa_vs30_insert(capa, 0x1);
+#if defined(MMCHS_VS33)
+    // According to the Spec, the card should support 2.7-3.6V
+    // chp 3.2 in PLS
+    capa = sdhc_capa_vs33_insert(capa, 0x1); // < NOT done by Free BSD
+#endif
+    sdhc_capa_wr(&sdhc, capa);
+    // .. and MMCHS_CUR_CAPA[23:0]
+    // This is not done by BSD code either!
+    // Also: a comment in the TRM says that this is not implemented
+
+    // MMC host and bust configuration
+    // TRM: see Figure 24-37, page 5116
+    // BSD: ti_mmchs_hw_init, line 1375, point 5
+    omap44xx_mmchs_CON_t con = omap44xx_mmchs_CON_rd(&mmchs);
+    // Set a couple of default values
+    con = omap44xx_mmchs_CON_OD_insert(con, 0x0);
+    con = omap44xx_mmchs_CON_DW8_insert(con, 0x0);
+    con = omap44xx_mmchs_CON_CEATA_insert(con, 0x0); // Standard, not ATA mode
+    // Written later
+
+    // Make sure SD bus power is not yet turned on
+    assert(sdhc_hctl_sdbp_rdf(&sdhc)==0x0);
+
+    // Get old configuration
+    sdhc_hctl_t hctl = sdhc_hctl_rd(&sdhc);
+
+    // Step 4
+    // ==================================================
+    // It seems that all cards need to support a bus width of 1
+    // SD card spec v1
+    // This is from the Free BSD code
+    uint32_t bus_width = 1;
+    switch (bus_width) {
+    case 1:
+        printf("mmchs: setting bus width to 1\n");
+        hctl = sdhc_hctl_dtw_insert(hctl, 0x0); // Data transfer width 0=1 Bit
+        con = omap44xx_mmchs_CON_DW8_insert(con, 0x0); // must be 0 for SD cards
+        break;
+    case 4:
+        printf("mmchs: setting bus width to 4\n");
+        hctl = sdhc_hctl_dtw_insert(hctl, 0x1); // Data transfer width 1=4 Bit
+        con = omap44xx_mmchs_CON_DW8_insert(con, 0x0); // must be 0 for SD cards
+        break;
+    case 8:
+        panic("DW8=1 (a bus width of 8) is not supported for SD cards");
+        con = omap44xx_mmchs_CON_DW8_insert(con, 0x1);
+        break;
+    default:
+        panic("Given bus width not supported\n");
+    }
+    
+    // Write configuration
+    omap44xx_mmchs_CON_wr(&mmchs, con);
+
+    // Step 5
+    // ==================================================
+    // XXX There seems to be a lot of redundancy with the previous setup ..
+#if defined(MMCHS_VS33)
+    hctl = sdhc_hctl_sdvs_insert(hctl, 0x7); // 0x7=3.3V
+#else
+    hctl = sdhc_hctl_sdvs_insert(hctl, 0x6); // 0x6=3.0V, 0x5=1.8V
+#endif
+    hctl = sdhc_hctl_sdbp_insert(hctl, 0x0); // Disable SD bus power
+    sdhc_hctl_wr(&sdhc, hctl);
+
+    // XXX Something happening with the TWL now, see BSE @ 1032
+    // Just ignore this for now
+
+    // Power on the BUS
+    sdhc_hctl_sdbp_wrf(&sdhc, 0x1);
+
+    // Wait for SDBP to come up
+    printf("mmchsh: turning on SD bus power .. ");
+    // Wait for init to be done
+    uint32_t sdbp_loop = 0;
+    while (sdhc_hctl_sdbp_rdf(&sdhc)==0x0) {
+        if (++sdbp_loop>1000) {
+            printf("\n");
+            print_mmchs();
+            panic("Timeout in setting SDBP");
+        }
+        mmchs_wait_msec(1);
+    }
+    printf("done (loop=%d)\n", sdbp_loop);
+
+    // Enable internal clock
+    // TRM Figure 24-37
+    sdhc_sysctl_ice_wrf(&sdhc, 0x1);
+
+    // Clock configuration
+    mmchs_set_frequency(0x3FF);
+
+    // BSD: get the clock from omap4_clk_hsmmc_get_source_freq
+    //          which is in arm/ti/omap4/omap4_prcm_clks.c
+    //          which then calls into omap4_clk_details
+    //          which returns 64 MHz or 96 MHz
+    
+    // Could not yet figure out what ios->clock is supposed to be ..
+    // Let's assume it is 1 ..
+    // In that case we need to divide by 1200 to get 80 kHz
+    // The closest we can get is 1023 ....
+
+    // Waiting for internal clock to become stable
+    int ics_loop = 0;
+    while (sdhc_sysctl_ics_rdf(&sdhc)!=1) {
+        ics_loop++;
+    }
+    printf("mmchs: internal clock stable .. %d loops\n", ics_loop);
+
+    // 0x3 means MMC1_ICLK=on and MMC1_FCLK=1 (see Table 24-9)
+    omap44xx_mmchs_SYSCONFIG_t sysconfig = omap44xx_mmchs_SYSCONFIG_rd(&mmchs);
+    /* sysconfig = omap44xx_mmchs_SYSCONFIG_AUTOIDLE_insert(sysconfig, 0x0); */
+    /* sysconfig = omap44xx_mmchs_SYSCONFIG_SIDLEMODE_insert(sysconfig, 0x1); */
+    sysconfig = omap44xx_mmchs_SYSCONFIG_CLOCKACTIVITY_insert(sysconfig, 0x3);
+    omap44xx_mmchs_SYSCONFIG_wr(&mmchs, sysconfig);
+    int clkactiv = 0;
+    while (omap44xx_mmchs_SYSCONFIG_CLOCKACTIVITY_rdf(&mmchs)!=0x3) {
+        clkactiv++;
+    }
+    printf("mmchs: clock acitivity enabled .. %d loops\n", clkactiv);
+
+    printf("mmchs: configuration done\n");
+    // EOF Figure 24-37
+}
+
+void mmchs_init(void)
+{
+    cm2_init();
+
+    mackerel_addr_t mmchs_vaddr = omap_dev_map(MMCHS_PADDR);
+    
+    // Initialize devices
+    omap44xx_mmchs_initialize(&mmchs, mmchs_vaddr);
+    sdhc_initialize(&sdhc, mmchs_vaddr + 0x200);
+    ctrlmod_init();
+
+    printf("\nmmchs: entered init().\n");
+
+    // Enable interrupts
+    gic_enable_interrupt(MMC1_IRQ,
+                         GIC_IRQ_CPU_TRG_BSP,
+                         0,//                         GIC_IRQ_PRIO_LOWEST,
+                         GIC_IRQ_LEVEL_SENSITIVE,
+                         GIC_IRQ_1_TO_N);
+
+    // Configure Pad multiplexing
+    // Does not change anything ctrlmod_init();
+
+    // Enable power
+    cm2_enable_hsmmc1();
+
+    // Configure device
+    mmchs_pre_configure();
+    mmchs_configure();
+
+    /* // Change clock frequency to 50 MHz (as Linux) */
+    /* mmchs_change_clock_frequency(0x2); */
+    /* mmchs_do_state_machine_reset(); */
+
+    switch (sdhc_rev_srev_rdf(&sdhc)) {
+    case 0x0:
+        printf("SD Host Specification Version 1.0\n");
+        break;
+    case 0x1:
+        printf("SD Host Specification Version 2.0\n");
+        break;
+    default:
+        panic("Don't understand SREV field");
+    }
+    
+
+    mmchs_init_stream();
+    mmchs_detect_card();
+    /* mmchs_init_and_ident_card(); */
+
+
+    /* printf("mmchs_detect_card\n"); */
+    /* /\* mmchs_detect_card(); *\/ */
+    /* sdhc_ie_wr(&sdhc, ~0x0); */
+    /* sdhc_ise_wr(&sdhc, ~0x0); */
+    
+    /* mmchs_print_power_state(); */
+
+    /* int resp; */
+    /* int loop = 0; */
+
+    /* do { */
+
+    /*     printf("Trying to init card, step %d\n", ++loop); */
+        
+    /*     /\* mmchs_wait_msec(100); *\/ */
+        
+    /*     /\* // See diagram 24-48 for details on how to set card frequency *\/ */
+    /*     /\* mmchs_change_clock_frequency(); *\/ */
+
+    /*     mmchs_wait_msec(100); */
+    /*     printf("Init and ident card .. \n"); */
+    /*     resp = mmchs_init_and_ident_card(); */
+
+    /*     mmchs_wait_msec(1000); */
+
+    /* } while(resp!=MMCHS_RESP_SUCCESS && loop<100); */
+
+}
+
+/*
+ * \brief Interrupt handler for MMC
+ *
+ * See TRM 24.4.4.1, page 5092
+ */
+void mmchs_handle_irq(void)
+{
+    printf("mmchs: got interrupt\n");
+
+    cm2_print_standby_state();
+    sdhc_stat_t stat = sdhc_stat_rd(&sdhc);
+
+    sdhc_stat_pr(PRBUFL, &sdhc);
+    printf("%s\n", PRBUF);
+
+    // Handle interrupt
+    if (sdhc_stat_bada_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt BADA\n");
+    }
+    else if (sdhc_stat_cerr_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CERR\n");
+    }
+    else if (sdhc_stat_admae_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt ADMAE\n");
+    }
+    else if (sdhc_stat_ace_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt ACE\n");
+    }
+    else if (sdhc_stat_deb_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt DEB\n");
+    }
+    else if (sdhc_stat_dcrc_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt DCRC\n");
+    }
+    else if (sdhc_stat_dto_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt DTO\n");
+    }
+    else if (sdhc_stat_cie_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CIE\n");
+    }
+    else if (sdhc_stat_ceb_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CEB\n");
+    }
+    else if (sdhc_stat_ccrc_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CCRC\n");
+    }
+    else if (sdhc_stat_cto_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CTO\n");
+    }
+    else if (sdhc_stat_erri_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt ERRI\n");
+    }
+    else if (sdhc_stat_intb_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt BSR\n");
+    }
+    else if (sdhc_stat_inta_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt OBI\n");
+    }
+    else if (sdhc_stat_cirq_extract(stat)==0x1) {
+        sdhc_ise_cirq_wrf(&sdhc, 0x0);
+        sdhc_ie_cirq_wrf(&sdhc, 0x0);
+        printf("Implement mmch interrupt handler action for interrupt CIRQ\n");
+    }
+    else if (sdhc_stat_crem_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CREM\n");
+    }
+    else if (sdhc_stat_cins_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CINS\n");
+    }
+    else if (sdhc_stat_brr_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt BRR\n");
+    }
+    else if (sdhc_stat_bwr_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt BWR\n");
+    }
+    else if (sdhc_stat_dma_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt DMA\n");
+    }
+    else if (sdhc_stat_bge_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt BGE\n");
+    }
+    else if (sdhc_stat_tc_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt TC\n");
+    }
+    else if (sdhc_stat_cc_extract(stat)==0x1) {
+        printf("Implement mmch interrupt handler action for interrupt CC\n");
+    }
+
+    // Unset STAT bits
+    sdhc_stat_wr(&sdhc, ~0x0);
+
+    // Acknowledge interrupt
+    gic_ack_irq(0x73);
+
+    // Activate interrupts again .. 
+    __asm volatile ("CPSIE aif");
+
+    // Never return ..
+    // XXX
+    while (1) ;
+}
diff --git a/usr/drivers/omap44xx/mmchs/omap44xx_cm2.h b/usr/drivers/omap44xx/mmchs/omap44xx_cm2.h
new file mode 100644 (file)
index 0000000..8ced14f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#ifndef __ARM_CM2_H__
+#define __ARM_CM2_H__
+
+#include <dev/omap/omap44xx_mmchs_dev.h>
+#include <dev/omap/omap44xx_ctrlmod_dev.h>
+
+// TRM Table 3-1286, page 918
+#define CM2_BASE   0x4A009300U
+#define CLKGEN_CM2_BASE  0x4A008100
+
+#define CM2_PADDR (0x4A009300U)
+#define CM2_CLKGEN_PADDR (0x4A008100)
+#define CM2_L4PER_PADDR (0x4A009400)
+
+// We need this because paging_arm_device returns the address 
+// of the beginning of the section in virtual memory ..
+// We map sections because we don't use the second level page table 
+// at this point yet. XXXX Is this actually true?
+#define omap_dev_map(p) \
+    (mackerel_addr_t) \
+    (paging_map_device(p, ARM_L1_SECTION_BYTES) \
+     + (p & ARM_L1_SECTION_MASK))
+
+void cm2_enable_i2c(int i2c_index);
+int  cm2_get_hsmmc1_base_clock(void);
+void print_cm2(void);
+void cm2_print_standby_state(void);
+
+void cm2_enable_hsmmc1(void);
+void cm2_init(void);
+
+#endif /* __ARM_CM2_H__ */
diff --git a/usr/drivers/omap44xx/mmchs/omap44xx_ctrlmod.h b/usr/drivers/omap44xx/mmchs/omap44xx_ctrlmod.h
new file mode 100644 (file)
index 0000000..edbdc84
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#ifndef __ARM_CTRLMOD_H__
+#define __ARM_CTRLMOD_H__
+
+#include <dev/omap/omap44xx_ctrlmod_dev.h>
+
+// afaict, the power enabling procedure is only possible in a
+// interrupt-driven way and we need the PBIAS interrupt -SG
+#define PBIAS_IRQ (32+75)
+
+// initialize registers
+void ctrlmod_init(void);
+// turn on sdmmc1 power
+void sdmmc1_enable_power(void);
+
+void pbias_handle_irq(void);
+
+#endif /* __ARM_CTRLMOD_H__ */
diff --git a/usr/drivers/omap44xx/mmchs/omap44xx_mmchs.h b/usr/drivers/omap44xx/mmchs/omap44xx_mmchs.h
new file mode 100644 (file)
index 0000000..a9e6c2a
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaetstr 6, CH-8092 Zurich.
+ */
+
+#ifndef __ARM_MMCHS_H__
+#define __ARM_MMCHS_H__
+
+#include <kernel.h>
+
+// Use 3.3 Volt for bus voltage
+// #define MMCHS_VS33 1
+
+// Base address of the MMC host controller
+// TRM Table 24-56, page 5140
+#define MMCHS_BASE 0x4809C000U
+
+/*
+ * List of commands
+ *
+ * see TRM MMCHS_CMD documentation, table 24-83, page 5160
+ * and SD card specification
+ */
+#define CMD0 0x0   // GO_IDLE_STATE / maybe also just a card reset ..
+#define CMD5 0x5   // SEND_OP_COND
+#define CMD8 0x8   // Detect v2 card, handshake voltage
+
+#define MMCHS_RESP_SUCCESS 0UL
+#define MMCHS_RESP_TIMEOUT 1UL
+
+#define CYCLES_PER_MSEC 1200000UL
+#define CYCLES_PER_SEC (1000*CYCLES_PER_MSEC)
+
+void        mmchs_send_cmd(int cmd_idx, uint32_t arg);
+void        mmchs_identify_card(void);
+int         mmchs_init_and_ident_card(void);
+
+static void mmchs_change_clock_frequency(int clkdiv);
+static int  mmchs_finalize_cmd(void);
+void mmchs_handle_irq(void);
+void mmchs_init(void);
+
+#define MMCHS_PADDR (0x4809C000U)
+
+// MMC1 interrupt, two lines
+//    (MM_IRQ_50 for Cortex-M3 INTC)
+//     MA_IRQ_83 for Cortex-A9 INTC
+// see Free BSD sys/arch/arm/ti/omap4/omap4_reg.h
+#define MMC1_IRQ (32+83) 
+
+#endif /* __ARM_MMCHS_H__ */