Needs to be changed to a user space driver.
"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
] ++
--- /dev/null
+/*
+ * 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);
+};
--- /dev/null
+/*
+ * 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";
+ };
+ };
--- /dev/null
+/*
+ * 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";
+ };
+
+ };
};
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" {
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.";
};
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." {
};
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) "" {
};
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) "" {
};
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) "" {
};
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";
};
};
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";
};
--- /dev/null
+/*
+ * 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";
+ };
+
+ };
--- /dev/null
+/*
+ * 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";
+ };
+};
--- /dev/null
+
+/*
+ * 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);
+};
// 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
"omap/omap44xx_id",
"omap/omap44xx_emif",
"omap/omap44xx_gpio"],
- addLibraries = [ "elf", "cpio", "fdif" ]
+ addLibraries = [ "elf", "cpio", "fdif", "mmchs" ]
}
]
#include <dev/pl130_gic_dev.h>
#include <arm_hal.h>
-
+#include <gic.h>
+
extern pl130_gic_t gic;
extern uint32_t it_num_lines;
/* } */
}
-
-// 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
*
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__
--- /dev/null
+--------------------------------------------------------------------------
+-- 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
--- /dev/null
+/*
+ * 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");
+ }
+}
+
--- /dev/null
+/*
+ * 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");
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+ /*
+ * 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) ;
+}
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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__ */