Merge "msm_shared: mipi: Add correct post dividers for DSI PLL"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index d95806c..9c01091 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -90,6 +90,8 @@
static const char *emmc_cmdline = " androidboot.emmc=true";
static const char *usb_sn_cmdline = " androidboot.serialno=";
+static const char *androidboot_mode = " androidboot.mode=";
+static const char *loglevel = " quiet";
static const char *battchg_pause = " androidboot.mode=charger";
static const char *auth_kernel = " androidboot.authorized_kernel=true";
@@ -185,6 +187,8 @@
int have_cmdline = 0;
unsigned char *cmdline_final = NULL;
int pause_at_bootup = 0;
+ char ffbm[10];
+ bool boot_into_ffbm = get_ffbm(ffbm, sizeof(ffbm));
if (cmdline && cmdline[0]) {
cmdline_len = strlen(cmdline);
@@ -197,7 +201,12 @@
cmdline_len += strlen(usb_sn_cmdline);
cmdline_len += strlen(sn_buf);
- if (target_pause_for_battery_charge()) {
+ if (boot_into_ffbm) {
+ cmdline_len += strlen(androidboot_mode);
+ cmdline_len += strlen(ffbm);
+ /* reduce kernel console messages to speed-up boot */
+ cmdline_len += strlen(loglevel);
+ } else if (target_pause_for_battery_charge()) {
pause_at_bootup = 1;
cmdline_len += strlen(battchg_pause);
}
@@ -273,7 +282,17 @@
have_cmdline = 1;
while ((*dst++ = *src++));
- if (pause_at_bootup) {
+ if (boot_into_ffbm) {
+ src = androidboot_mode;
+ if (have_cmdline) --dst;
+ while ((*dst++ = *src++));
+ src = ffbm;
+ if (have_cmdline) --dst;
+ while ((*dst++ = *src++));
+ src = loglevel;
+ if (have_cmdline) --dst;
+ while ((*dst++ = *src++));
+ } else if (pause_at_bootup) {
src = battchg_pause;
if (have_cmdline) --dst;
while ((*dst++ = *src++));
@@ -655,7 +674,7 @@
*/
void *dtb;
dtb = dev_tree_appended((void*) hdr->kernel_addr,
- (void *)hdr->tags_addr);
+ (void *)hdr->tags_addr, hdr->kernel_size);
if (!dtb) {
dprintf(CRITICAL, "ERROR: Appended Device Tree Blob not found\n");
return -1;
@@ -752,7 +771,7 @@
*/
void *dtb;
dtb = dev_tree_appended((void*) hdr->kernel_addr,
- (void *)hdr->tags_addr);
+ (void *)hdr->tags_addr, hdr->kernel_size);
if (!dtb) {
dprintf(CRITICAL, "ERROR: Appended Device Tree Blob not found\n");
return -1;
@@ -1285,7 +1304,7 @@
*/
if (!dtb_copied) {
void *dtb;
- dtb = dev_tree_appended((void *)hdr->kernel_addr, (void *)hdr->tags_addr);
+ dtb = dev_tree_appended((void *)hdr->kernel_addr, (void *)hdr->tags_addr, hdr->kernel_size);
if (!dtb) {
fastboot_fail("dtb not found");
return;
@@ -1419,6 +1438,11 @@
/* Read and skip over sparse image header */
sparse_header = (sparse_header_t *) data;
+ if ((sparse_header->total_blks * sparse_header->blk_sz) > size) {
+ fastboot_fail("size too large");
+ return;
+ }
+
data += sparse_header->file_hdr_sz;
if(sparse_header->file_hdr_sz > sizeof(sparse_header_t))
{
@@ -1528,7 +1552,7 @@
{
if(major_version >= 2)
{
- if( !strcmp(arg,"ssd") || !strcmp(arg,"tqs") )
+ if( !strcmp(arg, "ssd") || !strcmp(arg, "tqs") )
{
ret = encrypt_scm((uint32 **) &data, &sz);
if (ret != 0) {
@@ -1536,10 +1560,13 @@
return;
}
- ret = scm_protect_keystore((uint32 *) data, sz);
- if (ret != 0) {
- dprintf(CRITICAL, "ERROR: scm_protect_keystore Failed\n");
- return;
+ /* Protect only for SSD */
+ if (!strcmp(arg, "ssd")) {
+ ret = scm_protect_keystore((uint32 *) data, sz);
+ if (ret != 0) {
+ dprintf(CRITICAL, "ERROR: scm_protect_keystore Failed\n");
+ return;
+ }
}
}
else
@@ -1782,6 +1809,7 @@
unsigned reboot_mode = 0;
unsigned usb_init = 0;
unsigned sz = 0;
+ bool boot_into_fastboot = false;
/* Setup page size information for nand/emmc reads */
if (target_is_emmc_boot())
@@ -1806,61 +1834,72 @@
surf_udc_device.serialno = sn_buf;
/* Check if we should do something other than booting up */
- if (keys_get_state(KEY_HOME) != 0)
- boot_into_recovery = 1;
- if (keys_get_state(KEY_VOLUMEUP) != 0)
- boot_into_recovery = 1;
- if(!boot_into_recovery)
+ if (keys_get_state(KEY_VOLUMEUP) && keys_get_state(KEY_VOLUMEDOWN))
{
- if (keys_get_state(KEY_BACK) != 0)
- goto fastboot;
- if (keys_get_state(KEY_VOLUMEDOWN) != 0)
- goto fastboot;
+ dprintf(ALWAYS,"dload mode key sequence detected");
+ if (set_download_mode())
+ {
+ dprintf(CRITICAL,"dload mode not supported by target");
+ }
+ else
+ {
+ reboot_device(0);
+ dprintf(CRITICAL,"Failed to reboot into dload mode");
+ }
+ boot_into_fastboot = true;
}
-
+ if (!boot_into_fastboot)
+ {
+ if (keys_get_state(KEY_HOME) || keys_get_state(KEY_VOLUMEUP))
+ boot_into_recovery = 1;
+ if (!boot_into_recovery &&
+ (keys_get_state(KEY_BACK) || keys_get_state(KEY_VOLUMEDOWN)))
+ boot_into_fastboot = true;
+ }
#if NO_KEYPAD_DRIVER
if (fastboot_trigger())
- goto fastboot;
+ boot_into_fastboot = true;
#endif
reboot_mode = check_reboot_mode();
if (reboot_mode == RECOVERY_MODE) {
boot_into_recovery = 1;
} else if(reboot_mode == FASTBOOT_MODE) {
- goto fastboot;
+ boot_into_fastboot = true;
}
- if (target_is_emmc_boot())
+ if (!boot_into_fastboot)
{
- if(emmc_recovery_init())
- dprintf(ALWAYS,"error in emmc_recovery_init\n");
- if(target_use_signed_kernel())
+ if (target_is_emmc_boot())
{
- if((device.is_unlocked) || (device.is_tampered))
+ if(emmc_recovery_init())
+ dprintf(ALWAYS,"error in emmc_recovery_init\n");
+ if(target_use_signed_kernel())
{
- #ifdef TZ_TAMPER_FUSE
- set_tamper_fuse_cmd();
- #endif
- #if USE_PCOM_SECBOOT
- set_tamper_flag(device.is_tampered);
- #endif
+ if((device.is_unlocked) || (device.is_tampered))
+ {
+ #ifdef TZ_TAMPER_FUSE
+ set_tamper_fuse_cmd();
+ #endif
+ #if USE_PCOM_SECBOOT
+ set_tamper_flag(device.is_tampered);
+ #endif
+ }
}
+ boot_linux_from_mmc();
}
- boot_linux_from_mmc();
+ else
+ {
+ recovery_init();
+ #if USE_PCOM_SECBOOT
+ if((device.is_unlocked) || (device.is_tampered))
+ set_tamper_flag(device.is_tampered);
+ #endif
+ boot_linux_from_flash();
+ }
+ dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
+ "to fastboot mode.\n");
}
- else
- {
- recovery_init();
-#if USE_PCOM_SECBOOT
- if((device.is_unlocked) || (device.is_tampered))
- set_tamper_flag(device.is_tampered);
-#endif
- boot_linux_from_flash();
- }
- dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
- "to fastboot mode.\n");
-
-fastboot:
sz = target_get_max_flash_size();
diff --git a/app/aboot/recovery.c b/app/aboot/recovery.c
index fc14a7f..c96490f 100644
--- a/app/aboot/recovery.c
+++ b/app/aboot/recovery.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -37,6 +37,7 @@
#include <lib/ptable.h>
#include <dev/keys.h>
#include <platform.h>
+#include <target.h>
#include <partition_parser.h>
#include <mmc.h>
@@ -51,6 +52,7 @@
static const int MISC_PAGES = 3; // number of pages to save
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
static char buf[4096];
+
unsigned boot_into_recovery = 0;
extern void reset_device_info();
@@ -295,10 +297,11 @@
// get recovery message
if (get_recovery_message(&msg))
return -1;
- if (msg.command[0] != 0 && msg.command[0] != 255) {
- dprintf(INFO, "Recovery command: %.*s\n", sizeof(msg.command), msg.command);
- }
msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+ if (msg.command[0] != 0 && msg.command[0] != 255) {
+ dprintf(INFO,"Recovery command: %d %s\n",
+ sizeof(msg.command), msg.command);
+ }
if (!strcmp("boot-recovery",msg.command))
{
@@ -429,10 +432,15 @@
// get recovery message
if(emmc_get_recovery_msg(&msg))
return -1;
- if (msg.command[0] != 0 && msg.command[0] != 255) {
- dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command);
- }
msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+ if (msg.command[0] != 0 && msg.command[0] != 255) {
+ dprintf(INFO,"Recovery command: %d %s\n",
+ sizeof(msg.command), msg.command);
+ }
+
+ if (!strncmp(msg.command, "boot-recovery", strlen("boot-recovery"))) {
+ boot_into_recovery = 1;
+ }
if (!strcmp("update-radio",msg.command))
{
@@ -466,3 +474,193 @@
emmc_set_recovery_msg(&msg); // send recovery message
return 0;
}
+
+static int read_misc(unsigned page_offset, void *buf, unsigned size)
+{
+ const char *ptn_name = "misc";
+ void *scratch_addr = target_get_scratch_address();
+ unsigned offset;
+ unsigned aligned_size;
+
+ if (size == 0 || buf == NULL || scratch_addr == NULL)
+ return -1;
+
+ if (target_is_emmc_boot())
+ {
+ int index;
+ unsigned long long ptn;
+ unsigned long long ptn_size;
+
+ index = partition_get_index(ptn_name);
+ if (index == INVALID_PTN)
+ {
+ dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+ return -1;
+ }
+
+ ptn = partition_get_offset(index);
+ ptn_size = partition_get_size(index);
+
+ offset = page_offset * BLOCK_SIZE;
+ aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
+ if (ptn_size < offset + aligned_size)
+ {
+ dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
+ ptn_name);
+ return -1;
+ }
+
+ if (mmc_read(ptn + offset, (unsigned int *)scratch_addr, aligned_size))
+ {
+ dprintf(CRITICAL, "Reading MMC failed\n");
+ return -1;
+ }
+ }
+ else
+ {
+ struct ptentry *ptn;
+ struct ptable *ptable;
+ unsigned pagesize = flash_page_size();
+
+ ptable = flash_get_ptable();
+ if (ptable == NULL)
+ {
+ dprintf(CRITICAL, "Partition table not found\n");
+ return -1;
+ }
+
+ ptn = ptable_find(ptable, ptn_name);
+ if (ptn == NULL)
+ {
+ dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+ return -1;
+ }
+
+ offset = page_offset * pagesize;
+ aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
+ if (ptn->length < offset + aligned_size)
+ {
+ dprintf(CRITICAL, "Read request out of '%s' boundaries\n",
+ ptn_name);
+ return -1;
+ }
+
+ if (flash_read(ptn, offset, scratch_addr, aligned_size)) {
+ dprintf(CRITICAL, "Reading flash failed\n");
+ return -1;
+ }
+ }
+
+ if (scratch_addr != buf)
+ memcpy(buf, scratch_addr, size);
+
+ return 0;
+}
+
+int write_misc(unsigned page_offset, void *buf, unsigned size)
+{
+ const char *ptn_name = "misc";
+ void *scratch_addr = target_get_scratch_address();
+ unsigned offset;
+ unsigned aligned_size;
+
+ if (size == 0 || buf == NULL || scratch_addr == NULL)
+ return -1;
+
+ if (target_is_emmc_boot())
+ {
+ int index;
+ unsigned long long ptn;
+ unsigned long long ptn_size;
+
+ index = partition_get_index(ptn_name);
+ if (index == INVALID_PTN)
+ {
+ dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+ return -1;
+ }
+
+ ptn = partition_get_offset(index);
+ ptn_size = partition_get_size(index);
+
+ offset = page_offset * BLOCK_SIZE;
+ aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
+ if (ptn_size < offset + aligned_size)
+ {
+ dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
+ ptn_name);
+ return -1;
+ }
+
+ if (scratch_addr != buf)
+ memcpy(scratch_addr, buf, size);
+ if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
+ {
+ dprintf(CRITICAL, "Writing MMC failed\n");
+ return -1;
+ }
+ }
+ else
+ {
+ struct ptentry *ptn;
+ struct ptable *ptable;
+ unsigned pagesize = flash_page_size();
+
+ ptable = flash_get_ptable();
+ if (ptable == NULL)
+ {
+ dprintf(CRITICAL, "Partition table not found\n");
+ return -1;
+ }
+
+ ptn = ptable_find(ptable, ptn_name);
+ if (ptn == NULL)
+ {
+ dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
+ return -1;
+ }
+
+ offset = page_offset * pagesize;
+ aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
+ if (ptn->length < offset + aligned_size)
+ {
+ dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
+ ptn_name);
+ return -1;
+ }
+
+ if (scratch_addr != buf)
+ memcpy(scratch_addr, buf, size);
+ if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
+ dprintf(CRITICAL, "Writing flash failed\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+bool get_ffbm(char *ffbm, unsigned size)
+{
+ const char *ffbm_cmd = "ffbm-";
+ const unsigned ffbm_submode_size = 2;
+ unsigned ffbm_mode_size = strlen(ffbm_cmd) + ffbm_submode_size;
+
+ if (size < ffbm_mode_size + 1)
+ {
+ dprintf(CRITICAL, "Buffer too short to get FFBM string\n");
+ return false;
+ }
+
+ if (read_misc(0, ffbm, ffbm_mode_size))
+ {
+ dprintf(CRITICAL, "Error reading MISC partition\n");
+ return false;
+ }
+ ffbm[ffbm_mode_size] = 0;
+
+ if (!strncmp(ffbm, ffbm_cmd, strlen(ffbm_cmd)))
+ return true;
+
+ return false;
+}
diff --git a/app/aboot/recovery.h b/app/aboot/recovery.h
index 6037213..0d6289a 100644
--- a/app/aboot/recovery.h
+++ b/app/aboot/recovery.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -62,7 +62,7 @@
unsigned fail_bitmap_length;
};
-
+int write_misc(unsigned page_offset, void *buf, unsigned size);
int get_recovery_message(struct recovery_message *out);
int set_recovery_message(const struct recovery_message *in);
@@ -72,6 +72,8 @@
int recovery_init (void);
+bool get_ffbm(char *ffbm, unsigned size);
+
extern unsigned boot_into_recovery;
#endif
diff --git a/dev/panel/msm/mipi_sharp_video_qhd.c b/dev/panel/msm/mipi_sharp_video_qhd.c
new file mode 100644
index 0000000..c7699a0
--- /dev/null
+++ b/dev/panel/msm/mipi_sharp_video_qhd.c
@@ -0,0 +1,163 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdint.h>
+#include <msm_panel.h>
+#include <mipi_dsi.h>
+#include <sys/types.h>
+#include <err.h>
+#include <reg.h>
+#include <mdp4.h>
+
+int mipi_sharp_video_qhd_config(void *pdata)
+{
+ int ret = NO_ERROR;
+
+ /* 2 Lanes -- Enables Data Lane0, 1 */
+ uint8_t lane_en = 0x3;
+ uint64_t low_pwr_stop_mode = 0;
+
+ /* Needed or else will have blank line at top of display */
+ uint8_t eof_bllp_pwr = 0x9;
+
+ uint8_t interleav = 0;
+ struct lcdc_panel_info *lcdc = NULL;
+ struct msm_panel_info *pinfo = (struct msm_panel_info *)pdata;
+
+ if (!pinfo)
+ return ERR_INVALID_ARGS;
+
+ lcdc = &(pinfo->lcdc);
+ if (!lcdc)
+ return ERR_INVALID_ARGS;
+
+ ret = mipi_dsi_video_mode_config((pinfo->xres + lcdc->xres_pad),
+ (pinfo->yres + lcdc->yres_pad),
+ (pinfo->xres),
+ (pinfo->yres),
+ (lcdc->h_front_porch),
+ (lcdc->h_back_porch + lcdc->h_pulse_width),
+ (lcdc->v_front_porch),
+ (lcdc->v_back_porch + lcdc->v_pulse_width),
+ (lcdc->h_pulse_width),
+ (lcdc->v_pulse_width),
+ pinfo->mipi.dst_format,
+ pinfo->mipi.traffic_mode,
+ lane_en,
+ low_pwr_stop_mode,
+ eof_bllp_pwr,
+ interleav);
+ return ret;
+}
+
+int mipi_sharp_video_qhd_on()
+{
+ return NO_ERROR;
+}
+
+int mipi_sharp_video_qhd_off()
+{
+ return NO_ERROR;
+}
+
+static struct mdss_dsi_phy_ctrl dsi_video_mode_phy_db = {
+ /* 540x960, RGB888, 2 Lane 60 fps video mode */
+ /* regulator */
+ {0x07, 0x09, 0x03, 0x00, 0x20, 0x00, 0x01},
+ /* timing */
+ {0x46, 0x1d, 0x20, 0x00, 0x39, 0x3a, 0x21, 0x21,
+ 0x32, 0x03, 0x04, 0x00},
+ /* phy ctrl */
+ {0x5f, 0x00, 0x00, 0x10},
+ /* strength */
+ {0xff, 0x06},
+ /* bist control */
+ {0x00, 0x00, 0xb1, 0xff, 0x00, 0x00},
+ /* lanes config */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x97,
+ 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x01, 0x97,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x97,
+ 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x97,
+ 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xbb},
+};
+
+void mipi_sharp_video_qhd_init(struct msm_panel_info *pinfo)
+{
+ if (!pinfo)
+ return;
+
+ pinfo->xres = 540;
+ pinfo->yres = 960;
+ pinfo->type = MIPI_VIDEO_PANEL;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 24;
+ pinfo->lcdc.h_back_porch = 80;
+ pinfo->lcdc.h_front_porch = 48;
+ pinfo->lcdc.h_pulse_width = 32;
+ pinfo->lcdc.v_back_porch = 15;
+ pinfo->lcdc.v_front_porch = 3;
+ pinfo->lcdc.v_pulse_width = 10;
+ pinfo->lcdc.border_clr = 0; /* blk */
+ pinfo->lcdc.underflow_clr = 0xff; /* blue */
+ pinfo->lcdc.hsync_skew = 0;
+ pinfo->clk_rate = 500000000;
+
+ pinfo->mipi.mode = DSI_VIDEO_MODE;
+ pinfo->mipi.pulse_mode_hsa_he = FALSE;
+ pinfo->mipi.hfp_power_stop = FALSE;
+ pinfo->mipi.hbp_power_stop = FALSE;
+ pinfo->mipi.hsa_power_stop = FALSE;
+ pinfo->mipi.eof_bllp_power_stop = FALSE;
+ pinfo->mipi.bllp_power_stop = FALSE;
+ pinfo->mipi.traffic_mode = DSI_NON_BURST_SYNCH_PULSE;
+ pinfo->mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
+ pinfo->mipi.vc = 0;
+ pinfo->mipi.rgb_swap = DSI_RGB_SWAP_RGB;
+ pinfo->mipi.data_lane0 = TRUE;
+ pinfo->mipi.data_lane1 = TRUE;
+ pinfo->mipi.data_lane2 = FALSE;
+ pinfo->mipi.data_lane3 = FALSE;
+ pinfo->mipi.t_clk_post = 0x04;
+ pinfo->mipi.t_clk_pre = 0x1c;
+ pinfo->mipi.stream = 0; /* dma_p */
+ pinfo->mipi.mdp_trigger = 0;
+ pinfo->mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+ pinfo->mipi.frame_rate = 60;
+ pinfo->mipi.mdss_dsi_phy_db = &dsi_video_mode_phy_db;
+ pinfo->mipi.tx_eot_append = TRUE;
+ pinfo->mipi.num_of_lanes = 2;
+
+ pinfo->mipi.panel_cmds = sharp_qhd_video_mode_cmds;
+ pinfo->mipi.num_of_panel_cmds =
+ ARRAY_SIZE(sharp_qhd_video_mode_cmds);
+
+ pinfo->on = mipi_sharp_video_qhd_on;
+ pinfo->off = mipi_sharp_video_qhd_off;
+ pinfo->config = mipi_sharp_video_qhd_config;
+}
diff --git a/dev/panel/msm/rules.mk b/dev/panel/msm/rules.mk
index 4b596f6..f151744 100644
--- a/dev/panel/msm/rules.mk
+++ b/dev/panel/msm/rules.mk
@@ -23,5 +23,6 @@
ifeq ($(PLATFORM),msm8974)
OBJS += \
- $(LOCAL_DIR)/mipi_toshiba_video_720p.o
+ $(LOCAL_DIR)/mipi_toshiba_video_720p.o \
+ $(LOCAL_DIR)/mipi_sharp_video_qhd.o
endif
diff --git a/include/platform.h b/include/platform.h
index 191077e..1c5b27e 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -50,6 +50,6 @@
unsigned check_reboot_mode(void);
void platform_uninit_timer(void);
void reboot_device(unsigned);
-
+int set_download_mode(void);
#endif
diff --git a/include/target.h b/include/target.h
index b9dde60..6c4486d 100644
--- a/include/target.h
+++ b/include/target.h
@@ -1,6 +1,8 @@
/*
* Copyright (c) 2008 Travis Geiselbrecht
*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
@@ -46,6 +48,7 @@
unsigned target_baseband(void);
void target_serialno(unsigned char *buf);
void target_fastboot_init(void);
+struct mmc_device *target_mmc_device();
#endif
diff --git a/platform/mdm9x25/acpuclock.c b/platform/mdm9x25/acpuclock.c
index cf8486d..5812db6 100644
--- a/platform/mdm9x25/acpuclock.c
+++ b/platform/mdm9x25/acpuclock.c
@@ -47,9 +47,6 @@
ASSERT(iclk);
ASSERT(cclk);
- /* Disable USB boot clock */
- writel(0, USB_BOOT_CLOCK_CTL);
-
/* Disable interface and core clk */
clk_disable(iclk);
clk_disable(cclk);
diff --git a/platform/mdm9x25/include/platform/iomap.h b/platform/mdm9x25/include/platform/iomap.h
index 5dfa761..ac0d424 100644
--- a/platform/mdm9x25/include/platform/iomap.h
+++ b/platform/mdm9x25/include/platform/iomap.h
@@ -124,6 +124,4 @@
#define USB_HS_SYSTEM_CMD_RCGR (CLK_CTL_BASE + 0x490)
#define USB_HS_SYSTEM_CFG_RCGR (CLK_CTL_BASE + 0x494)
-#define USB_BOOT_CLOCK_CTL (CLK_CTL_BASE + 0x1A00)
-
#endif
diff --git a/platform/msm8226/acpuclock.c b/platform/msm8226/acpuclock.c
index 96e8687..a9e14e3 100644
--- a/platform/msm8226/acpuclock.c
+++ b/platform/msm8226/acpuclock.c
@@ -118,9 +118,6 @@
snprintf(clk_name, 64, "sdc%u_core_clk", interface);
- /* Disalbe MCI_CLK before changing the sdcc clock */
- mmc_boot_mci_clk_disable();
-
if(freq == MMC_CLK_400KHZ)
{
ret = clk_get_set_enable(clk_name, 400000, 1);
@@ -129,6 +126,10 @@
{
ret = clk_get_set_enable(clk_name, 50000000, 1);
}
+ else if(freq == MMC_CLK_200MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 200000000, 1);
+ }
else
{
dprintf(CRITICAL, "sdc frequency (%d) is not supported\n", freq);
@@ -141,9 +142,6 @@
dprintf(CRITICAL, "failed to set sdc1_core_clk ret = %d\n", ret);
ASSERT(0);
}
-
- /* Enable MCI CLK */
- mmc_boot_mci_clk_enable();
}
/* Configure UART clock based on the UART block id*/
diff --git a/platform/msm8226/include/platform/gpio.h b/platform/msm8226/include/platform/gpio.h
index ac554da..02849ab 100644
--- a/platform/msm8226/include/platform/gpio.h
+++ b/platform/msm8226/include/platform/gpio.h
@@ -30,6 +30,7 @@
#define __PLATFORM_MSM8226_GPIO_H
#include <bits.h>
+#include <gpio.h>
/* GPIO TLMM: Direction */
#define GPIO_INPUT 0
diff --git a/platform/msm8226/include/platform/iomap.h b/platform/msm8226/include/platform/iomap.h
index d459984..2fe4b42 100644
--- a/platform/msm8226/include/platform/iomap.h
+++ b/platform/msm8226/include/platform/iomap.h
@@ -39,7 +39,10 @@
#define APPS_SS_BASE 0xF9000000
#define SYSTEM_IMEM_BASE 0xFE800000
-#define RESTART_REASON_ADDR (SYSTEM_IMEM_BASE + 0x565C)
+#define MSM_SHARED_IMEM_BASE 0xFE805000
+
+#define RESTART_REASON_ADDR (MSM_SHARED_IMEM_BASE + 0x65C)
+#define FORCE_DLOAD_MODE_ADDR (MSM_SHARED_IMEM_BASE + 0xFE0)
#define MSM_GIC_DIST_BASE APPS_SS_BASE
#define MSM_GIC_CPU_BASE (APPS_SS_BASE + 0x2000)
@@ -51,13 +54,16 @@
#define MSM_SDC1_BAM_BASE (PERIPH_SS_BASE + 0x00004000)
#define MSM_SDC1_BASE (PERIPH_SS_BASE + 0x00024000)
+#define MSM_SDC1_SDHCI_BASE (PERIPH_SS_BASE + 0x00024900)
#define MSM_SDC1_DML_BASE (PERIPH_SS_BASE + 0x00024800)
#define MSM_SDC3_BAM_BASE (PERIPH_SS_BASE + 0x00044000)
#define MSM_SDC3_BASE (PERIPH_SS_BASE + 0x00064000)
+#define MSM_SDC3_SDHCI_BASE (PERIPH_SS_BASE + 0x00064900)
#define MSM_SDC3_DML_BASE (PERIPH_SS_BASE + 0x00064800)
#define MSM_SDC2_BAM_BASE (PERIPH_SS_BASE + 0x00084000)
#define MSM_SDC2_BASE (PERIPH_SS_BASE + 0x000A4000)
#define MSM_SDC2_DML_BASE (PERIPH_SS_BASE + 0x000A4800)
+#define MSM_SDC2_SDHCI_BASE (PERIPH_SS_BASE + 0x000A4900)
#define BLSP1_UART0_BASE (PERIPH_SS_BASE + 0x0011D000)
#define BLSP1_UART1_BASE (PERIPH_SS_BASE + 0x0011E000)
@@ -127,4 +133,11 @@
#define USB_HS_SYSTEM_CMD_RCGR (CLK_CTL_BASE + 0x490)
#define USB_HS_SYSTEM_CFG_RCGR (CLK_CTL_BASE + 0x494)
+/* SDHCI */
+#define SDCC_MCI_HC_MODE (PERIPH_SS_BASE + 0x00024078)
+#define SDCC_HC_PWRCTL_MASK_REG (PERIPH_SS_BASE + 0x000240E0)
+#define SDCC_HC_PWRCTL_CTL_REG (PERIPH_SS_BASE + 0x000240E8)
+
+/* DRV strength for sdcc */
+#define SDC1_HDRV_PULL_CTL (TLMM_BASE_ADDR + 0x00002044)
#endif
diff --git a/platform/msm8226/include/platform/irqs.h b/platform/msm8226/include/platform/irqs.h
index c490a0b..2e29d3a 100644
--- a/platform/msm8226/include/platform/irqs.h
+++ b/platform/msm8226/include/platform/irqs.h
@@ -47,6 +47,8 @@
#define USB1_HS_BAM_IRQ (GIC_SPI_START + 135)
#define USB1_HS_IRQ (GIC_SPI_START + 134)
+#define SDCC_PWRCTRL_IRQ (GIC_SPI_START + 138)
+
/* Retrofit universal macro names */
#define INT_USB_HS USB1_HS_IRQ
diff --git a/platform/msm8974/acpuclock.c b/platform/msm8974/acpuclock.c
index ef04fbc..215e1d9 100644
--- a/platform/msm8974/acpuclock.c
+++ b/platform/msm8974/acpuclock.c
@@ -120,7 +120,9 @@
snprintf(clk_name, 64, "sdc%u_core_clk", interface);
/* Disalbe MCI_CLK before changing the sdcc clock */
+#ifndef MMC_SDHCI_SUPPORT
mmc_boot_mci_clk_disable();
+#endif
if(freq == MMC_CLK_400KHZ)
{
@@ -134,6 +136,10 @@
{
ret = clk_get_set_enable(clk_name, 100000000, 1);
}
+ else if(freq == MMC_CLK_200MHZ)
+ {
+ ret = clk_get_set_enable(clk_name, 200000000, 1);
+ }
else
{
dprintf(CRITICAL, "sdc frequency (%d) is not supported\n", freq);
@@ -148,7 +154,9 @@
}
/* Enalbe MCI clock */
+#ifndef MMC_SDHCI_SUPPORT
mmc_boot_mci_clk_enable();
+#endif
}
/* Configure UART clock based on the UART block id*/
diff --git a/platform/msm8974/gpio.c b/platform/msm8974/gpio.c
index d36cd6d..13097da 100644
--- a/platform/msm8974/gpio.c
+++ b/platform/msm8974/gpio.c
@@ -89,32 +89,3 @@
};
}
}
-
-static void tlmm_set_sdc_pins(struct tlmm_cfgs *cfg)
-{
- uint32_t reg_val;
-
- reg_val = readl(SDC1_HDRV_PULL_CTL);
-
- reg_val &= ~(cfg->mask << cfg->off);
-
- reg_val |= (cfg->val << cfg->off);
-
- writel(reg_val, SDC1_HDRV_PULL_CTL);
-}
-
-void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *hdrv_cfgs, uint8_t sz)
-{
- uint8_t i;
-
- for (i = 0; i < sz; i++)
- tlmm_set_sdc_pins(&hdrv_cfgs[i]);
-}
-
-void tlmm_set_pull_ctrl(struct tlmm_cfgs *pull_cfgs, uint8_t sz)
-{
- uint8_t i;
-
- for (i = 0; i < sz; i++)
- tlmm_set_sdc_pins(&pull_cfgs[i]);
-}
diff --git a/platform/msm8974/include/platform/gpio.h b/platform/msm8974/include/platform/gpio.h
index 8c4bba8..8dc68f2 100644
--- a/platform/msm8974/include/platform/gpio.h
+++ b/platform/msm8974/include/platform/gpio.h
@@ -29,6 +29,8 @@
#ifndef __PLATFORM_COPPER_GPIO_H
#define __PLATFORM_COPPER_GPIO_H
+#include <gpio.h>
+
/* GPIO TLMM: Direction */
#define GPIO_INPUT 0
#define GPIO_OUTPUT 1
@@ -53,36 +55,6 @@
#define GPIO_ENABLE 0
#define GPIO_DISABLE 1
-#define TLMM_PULL_MASK 0x3
-#define TLMM_HDRV_MASK 0x7
-
-enum {
- TLMM_CUR_VAL_16MA = 0x7,
- TLMM_CUR_VAL_10MA = 0x4,
-} tlmm_drive_config;
-
-enum {
- TLMM_PULL_UP = 0x3,
- TLMM_NO_PULL = 0x0,
-} tlmm_pull_values;
-
-enum {
- SDC1_DATA_HDRV_CTL_OFF = 0,
- SDC1_CMD_HDRV_CTL_OFF = 3,
- SDC1_CLK_HDRV_CTL_OFF = 6,
- SDC1_DATA_PULL_CTL_OFF = 9,
- SDC1_CMD_PULL_CTL_OFF = 11,
- SDC1_CLK_PULL_CTL_OFF = 13,
-} tlmm_drv_ctrl;
-
-struct tlmm_cfgs {
- uint32_t off;
- uint8_t val;
- uint8_t mask;
-};
-
void gpio_config_uart_dm(uint8_t id);
void gpio_config_blsp_i2c(uint8_t, uint8_t);
-void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *, uint8_t);
-void tlmm_set_pull_ctrl(struct tlmm_cfgs *, uint8_t);
#endif
diff --git a/platform/msm8974/include/platform/iomap.h b/platform/msm8974/include/platform/iomap.h
index b873889..12f0015 100644
--- a/platform/msm8974/include/platform/iomap.h
+++ b/platform/msm8974/include/platform/iomap.h
@@ -44,6 +44,8 @@
#define RESTART_REASON_ADDR (RPM_MSG_RAM_BASE + 0x65C)
#define RESTART_REASON_ADDR_V2 (MSM_SHARED_IMEM_BASE + 0x65C)
+#define FORCE_DLOAD_MODE_ADDR_V2 (MSM_SHARED_IMEM_BASE + 0xFE0)
+
#define KPSS_BASE 0xF9000000
#define MSM_GIC_DIST_BASE KPSS_BASE
@@ -61,15 +63,19 @@
#define MSM_SDC1_BAM_BASE (PERIPH_SS_BASE + 0x00004000)
#define MSM_SDC1_BASE (PERIPH_SS_BASE + 0x00024000)
#define MSM_SDC1_DML_BASE (PERIPH_SS_BASE + 0x00024800)
+#define MSM_SDC1_SDHCI_BASE (PERIPH_SS_BASE + 0x00024900)
#define MSM_SDC3_BAM_BASE (PERIPH_SS_BASE + 0x00044000)
#define MSM_SDC3_BASE (PERIPH_SS_BASE + 0x00064000)
#define MSM_SDC3_DML_BASE (PERIPH_SS_BASE + 0x00064800)
+#define MSM_SDC3_SDHCI_BASE (PERIPH_SS_BASE + 0x00064900)
#define MSM_SDC2_BAM_BASE (PERIPH_SS_BASE + 0x00084000)
#define MSM_SDC2_BASE (PERIPH_SS_BASE + 0x000A4000)
#define MSM_SDC2_DML_BASE (PERIPH_SS_BASE + 0x000A4800)
+#define MSM_SDC2_SDHCI_BASE (PERIPH_SS_BASE + 0x000A4900)
#define MSM_SDC4_BAM_BASE (PERIPH_SS_BASE + 0x000C4000)
#define MSM_SDC4_BASE (PERIPH_SS_BASE + 0x000E4000)
#define MSM_SDC4_DML_BASE (PERIPH_SS_BASE + 0x000E4800)
+#define MSM_SDC4_SDHCI_BASE (PERIPH_SS_BASE + 0x000E4900)
#define BLSP1_UART0_BASE (PERIPH_SS_BASE + 0x0011D000)
#define BLSP1_UART1_BASE (PERIPH_SS_BASE + 0x0011E000)
@@ -168,4 +174,9 @@
/* DRV strength for sdcc */
#define SDC1_HDRV_PULL_CTL (TLMM_BASE_ADDR + 0x00002044)
+
+/* SDHCI */
+#define SDCC_MCI_HC_MODE (PERIPH_SS_BASE + 0x00024078)
+#define SDCC_HC_PWRCTL_MASK_REG (PERIPH_SS_BASE + 0x000240E0)
+#define SDCC_HC_PWRCTL_CTL_REG (PERIPH_SS_BASE + 0x000240E8)
#endif
diff --git a/platform/msm8974/include/platform/irqs.h b/platform/msm8974/include/platform/irqs.h
index e6b7cf7..56ef1cb 100644
--- a/platform/msm8974/include/platform/irqs.h
+++ b/platform/msm8974/include/platform/irqs.h
@@ -66,4 +66,5 @@
((GIC_SPI_START + 95) + qup_id):\
((GIC_SPI_START + 101) + qup_id))
+#define SDCC_PWRCTRL_IRQ (GIC_SPI_START + 138)
#endif /* __IRQS_COPPER_H */
diff --git a/platform/msm_shared/debug.c b/platform/msm_shared/debug.c
index 8adb6ce..36dc420 100644
--- a/platform/msm_shared/debug.c
+++ b/platform/msm_shared/debug.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
- * Copyright (c) 2009, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,14 +35,30 @@
#include <arch/arm/dcc.h>
#include <dev/fbcon.h>
#include <dev/uart.h>
+#include <platform/timer.h>
+static void write_dcc(char c)
+{
+ uint32_t timeout = 10;
+
+ /* Note: Smallest sampling rate for DCC is 50us.
+ * This can be changed by SNOOPer.Rate on T32 window.
+ */
+ while (timeout)
+ {
+ if (dcc_putc(c) == 0)
+ break;
+ udelay(50);
+ timeout--;
+ }
+}
void _dputc(char c)
{
#if WITH_DEBUG_DCC
if (c == '\n') {
- while (dcc_putc('\r') < 0) ;
+ write_dcc('\r');
}
- while (dcc_putc(c) < 0) ;
+ write_dcc(c) ;
#endif
#if WITH_DEBUG_UART
uart_putc(0, c);
diff --git a/platform/msm_shared/dev_tree.c b/platform/msm_shared/dev_tree.c
index 773c81b..a2ef426 100644
--- a/platform/msm_shared/dev_tree.c
+++ b/platform/msm_shared/dev_tree.c
@@ -45,30 +45,44 @@
*
* Arguments: kernel - Start address of the kernel loaded in RAM
* tags - Start address of the tags loaded in RAM
+ * kernel_size - Size of the kernel in bytes
+ *
* Return Value: DTB address : If appended device tree is found
* 'NULL' : Otherwise
*/
-void *dev_tree_appended(void *kernel, void *tags)
+void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size)
{
uint32_t app_dtb_offset = 0;
- uint32_t dtb_magic = 0;
memcpy((void*) &app_dtb_offset, (void*) (kernel + DTB_OFFSET), sizeof(uint32_t));
- memcpy((void*) &dtb_magic, (void*) (kernel + app_dtb_offset), sizeof(uint32_t));
- if (dtb_magic == DTB_MAGIC) {
- void *dtb;
- int rc;
+ /*
+ * Check if we have valid offset for the DTB, if not return error.
+ * If the kernel image does not have appeneded device tree, DTB offset
+ * might contain some random address which is not accessible & cause
+ * data abort. If kernel start + dtb offset address exceed the total
+ * size of the kernel, then we dont have an appeneded DTB.
+ */
+ if (app_dtb_offset < kernel_size)
+ {
+ if (!fdt_check_header((void*) (kernel + app_dtb_offset)))
+ {
+ void *dtb;
+ int rc;
- dprintf(INFO, "Found Appeneded Flattened Device tree\n");
- dtb = kernel + app_dtb_offset;
- rc = fdt_open_into(dtb, tags, fdt_totalsize(dtb));
- if (rc == 0) {
- /* clear out the old DTB magic so kernel doesn't find it */
- *((uint32_t *)dtb) = 0;
- return tags;
+ dprintf(INFO, "Found Appeneded Flattened Device tree\n");
+ dtb = kernel + app_dtb_offset;
+ rc = fdt_open_into(dtb, tags, fdt_totalsize(dtb));
+ if (rc == 0)
+ {
+ /* clear out the old DTB magic so kernel doesn't find it */
+ *((uint32_t *)dtb) = 0;
+ return tags;
+ }
}
}
+ else
+ dprintf(CRITICAL, "DTB offset is incorrect, kernel image does not have appended DTB\n");
return NULL;
}
diff --git a/platform/msm_shared/dload_util.c b/platform/msm_shared/dload_util.c
new file mode 100644
index 0000000..4b7d08b
--- /dev/null
+++ b/platform/msm_shared/dload_util.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <reg.h>
+
+#define FORCE_DLOAD_COOKIE_0 0x322A4F99
+#define FORCE_DLOAD_COOKIE_1 0xC67E4350
+#define FORCE_DLOAD_COOKIE_2 0x77777777
+
+extern void dsb();
+
+void dload_util_write_cookie(uint32_t target_dload_mode_addr)
+{
+ writel(FORCE_DLOAD_COOKIE_0, target_dload_mode_addr);
+ writel(FORCE_DLOAD_COOKIE_1, target_dload_mode_addr + sizeof(uint32_t));
+ writel(FORCE_DLOAD_COOKIE_2, target_dload_mode_addr + 2 * sizeof(uint32_t));
+
+ dsb();
+}
diff --git a/platform/msm_shared/gpio.c b/platform/msm_shared/gpio.c
new file mode 100644
index 0000000..137f00a
--- /dev/null
+++ b/platform/msm_shared/gpio.c
@@ -0,0 +1,62 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <reg.h>
+#include <bits.h>
+#include <platform/iomap.h>
+#include <gpio.h>
+
+static void tlmm_set_sdc_pins(struct tlmm_cfgs *cfg)
+{
+ uint32_t reg_val;
+
+ reg_val = readl(SDC1_HDRV_PULL_CTL);
+
+ reg_val &= ~(cfg->mask << cfg->off);
+
+ reg_val |= (cfg->val << cfg->off);
+
+ writel(reg_val, SDC1_HDRV_PULL_CTL);
+}
+
+void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *hdrv_cfgs, uint8_t sz)
+{
+ uint8_t i;
+
+ for (i = 0; i < sz; i++)
+ tlmm_set_sdc_pins(&hdrv_cfgs[i]);
+}
+
+void tlmm_set_pull_ctrl(struct tlmm_cfgs *pull_cfgs, uint8_t sz)
+{
+ uint8_t i;
+
+ for (i = 0; i < sz; i++)
+ tlmm_set_sdc_pins(&pull_cfgs[i]);
+}
diff --git a/platform/msm_shared/include/dev_tree.h b/platform/msm_shared/include/dev_tree.h
index a27fafd..2c216aa 100644
--- a/platform/msm_shared/include/dev_tree.h
+++ b/platform/msm_shared/include/dev_tree.h
@@ -67,5 +67,5 @@
struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *);
int update_device_tree(void *, const char *, void *, unsigned);
int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t size, uint32_t addr);
-void *dev_tree_appended(void *kernel, void *tags);
+void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size);
#endif
diff --git a/platform/msm_shared/include/dload_util.h b/platform/msm_shared/include/dload_util.h
new file mode 100644
index 0000000..71d045d
--- /dev/null
+++ b/platform/msm_shared/include/dload_util.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DLOAD_UTIL_H
+#define __DLOAD_UTIL_H
+
+#include <sys/types.h>
+
+void dload_util_write_cookie(uint32_t target_dload_mode_addr);
+
+#endif
diff --git a/platform/msm_shared/include/gpio.h b/platform/msm_shared/include/gpio.h
new file mode 100644
index 0000000..2a95eda
--- /dev/null
+++ b/platform/msm_shared/include/gpio.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _GPIO_H_
+#define _GPIO_H_
+
+#define TLMM_PULL_MASK 0x3
+#define TLMM_HDRV_MASK 0x7
+
+/* Current values for tlmm pins */
+enum {
+ TLMM_CUR_VAL_16MA = 0x7,
+ TLMM_CUR_VAL_10MA = 0x4,
+} tlmm_drive_config;
+
+enum {
+ TLMM_PULL_UP = 0x3,
+ TLMM_NO_PULL = 0x0,
+} tlmm_pull_values;
+
+/* Bit offsets in the TLMM register */
+enum {
+ SDC1_DATA_HDRV_CTL_OFF = 0,
+ SDC1_CMD_HDRV_CTL_OFF = 3,
+ SDC1_CLK_HDRV_CTL_OFF = 6,
+ SDC1_DATA_PULL_CTL_OFF = 9,
+ SDC1_CMD_PULL_CTL_OFF = 11,
+ SDC1_CLK_PULL_CTL_OFF = 13,
+} tlmm_drv_ctrl;
+
+/* Input for the tlmm config function */
+struct tlmm_cfgs {
+ uint32_t off; /* Bit offeset in the register */
+ uint8_t val; /* Current value */
+ uint8_t mask; /* Mask for the clk/dat/cmd control */
+};
+
+/* APIs: exposed for other drivers */
+/* API: Hdrive control for tlmm pins */
+void tlmm_set_hdrive_ctrl(struct tlmm_cfgs *, uint8_t);
+/* API: Pull control for tlmm pins */
+void tlmm_set_pull_ctrl(struct tlmm_cfgs *, uint8_t);
+#endif
diff --git a/platform/msm_shared/include/mipi_dsi.h b/platform/msm_shared/include/mipi_dsi.h
index c067714..ba74946 100644
--- a/platform/msm_shared/include/mipi_dsi.h
+++ b/platform/msm_shared/include/mipi_dsi.h
@@ -72,6 +72,7 @@
#define DSI_CAL_STRENGTH_CTRL REG_DSI(0x100)
#define DSI_CMD_MODE_DMA_SW_TRIGGER REG_DSI(0x08C)
#define DSI_CMD_MODE_MDP_SW_TRIGGER REG_DSI(0x090)
+#define DSI_HS_TIMER_CTRL REG_DSI(0x0B8)
#define DSI_LANE_CTRL REG_DSI(0x0A8)
@@ -869,6 +870,24 @@
{sizeof(novatek_panel_set_led_pwm3), novatek_panel_set_led_pwm3}
};
+static struct mipi_dsi_cmd sharp_qhd_video_mode_cmds[] = {
+ {sizeof(novatek_panel_sw_reset), novatek_panel_sw_reset}
+ ,
+ {sizeof(novatek_panel_exit_sleep), novatek_panel_exit_sleep}
+ ,
+ {sizeof(novatek_panel_display_on), novatek_panel_display_on}
+ ,
+ {sizeof(novatek_panel_set_twolane), novatek_panel_set_twolane}
+ ,
+ {sizeof(novatek_panel_rgb_888), novatek_panel_rgb_888}
+ ,
+ {sizeof(novatek_panel_set_led_pwm1), novatek_panel_set_led_pwm1}
+ ,
+ {sizeof(novatek_panel_set_led_pwm2), novatek_panel_set_led_pwm2}
+ ,
+ {sizeof(novatek_panel_set_led_pwm3), novatek_panel_set_led_pwm3}
+};
+
static struct mipi_dsi_phy_ctrl mipi_dsi_novatek_panel_phy_ctrl = {
/* DSI_BIT_CLK at 500MHz, 2 lane, RGB888 */
{0x03, 0x01, 0x01, 0x00}, /* regulator */
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index 529d2c3..f1c9762 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -29,6 +29,10 @@
#ifndef __MMC_H__
#define __MMC_H__
+#if MMC_SDHCI_SUPPORT
+#include "mmc_sdhci.h"
+#include "mmc_wrapper.h"
+#else
#ifndef MMC_SLOT
#define MMC_SLOT 0
#endif
@@ -615,3 +619,4 @@
uint8_t card_supports_hs200_mode();
uint64_t mmc_get_device_capacity();
#endif
+#endif
diff --git a/platform/msm_shared/include/mmc_sdhci.h b/platform/msm_shared/include/mmc_sdhci.h
new file mode 100644
index 0000000..99174bf
--- /dev/null
+++ b/platform/msm_shared/include/mmc_sdhci.h
@@ -0,0 +1,221 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MMC_SDHCI_H__
+#define __MMC_SDHCI_H__
+
+#include <sdhci.h>
+
+/* Emmc Card bus commands */
+#define CMD0_GO_IDLE_STATE 0
+#define CMD1_SEND_OP_COND 1
+#define CMD2_ALL_SEND_CID 2
+#define CMD3_SEND_RELATIVE_ADDR 3
+#define CMD4_SET_DSR 4
+#define CMD6_SWITCH_FUNC 6
+#define CMD7_SELECT_DESELECT_CARD 7
+#define CMD8_SEND_EXT_CSD 8
+#define CMD9_SEND_CSD 9
+#define CMD10_SEND_CID 10
+#define CMD12_STOP_TRANSMISSION 12
+#define CMD13_SEND_STATUS 13
+#define CMD15_GO_INACTIVE_STATUS 15
+#define CMD16_SET_BLOCKLEN 16
+#define CMD17_READ_SINGLE_BLOCK 17
+#define CMD18_READ_MULTIPLE_BLOCK 18
+#define CMD23_SET_BLOCK_COUNT 23
+#define CMD24_WRITE_SINGLE_BLOCK 24
+#define CMD25_WRITE_MULTIPLE_BLOCK 25
+#define CMD28_SET_WRITE_PROTECT 28
+#define CMD29_CLEAR_WRITE_PROTECT 29
+#define CMD31_SEND_WRITE_PROT_TYPE 31
+#define CMD32_ERASE_WR_BLK_START 32
+#define CMD33_ERASE_WR_BLK_END 33
+#define CMD35_ERASE_GROUP_START 35
+#define CMD36_ERASE_GROUP_END 36
+#define CMD38_ERASE 38
+
+/* Card type */
+#define MMC_TYPE_STD_SD 0
+#define MMC_TYPE_SDHC 1
+#define MMC_TYPE_SDIO 2
+#define MMC_TYPE_MMCHC 3
+#define MMC_TYPE_STD_MMC 4
+
+/* OCR Register */
+#define MMC_OCR_17_19 (1 << 7)
+#define MMC_OCR_27_36 (0x1FF << 15)
+#define MMC_OCR_SEC_MODE (2 << 29)
+#define MMC_OCR_BUSY (1 << 31)
+
+/* Card status */
+#define MMC_CARD_STATUS(x) ((x >> 9) & 0x0F)
+#define MMC_TRAN_STATE 4
+#define MMC_PROG_STATE 7
+#define MMC_SWITCH_FUNC_ERR_FLAG (1 << 7)
+#define MMC_STATUS_INACTIVE 0
+#define MMC_STATUS_ACTIVE 1
+
+/* EXT_CSD */
+/* Offsets in the ext csd */
+#define MMC_EXT_MMC_BUS_WIDTH 183
+#define MMC_EXT_MMC_HS_TIMING 185
+#define MMC_DEVICE_TYPE 196
+#define MMC_EXT_HC_WP_GRP_SIZE 221
+#define MMC_SEC_COUNT4 215
+#define MMC_SEC_COUNT3 214
+#define MMC_SEC_COUNT2 213
+#define MMC_SEC_COUNT1 212
+#define MMC_PART_CONFIG 179
+#define MMC_ERASE_GRP_DEF 175
+#define MMC_USR_WP 171
+
+/* Values for ext csd fields */
+#define MMC_HS_TIMING 0x1
+#define MMC_HS200_TIMING 0x2
+#define MMC_ACCESS_WRITE 0x3
+#define MMC_HS_DDR_MODE (BIT(2) | BIT(3))
+#define MMC_HS_HS200_MODE (BIT(4) | BIT(5))
+#define MMC_SEC_COUNT4_SHIFT 24
+#define MMC_SEC_COUNT3_SHIFT 16
+#define MMC_SEC_COUNT2_SHIFT 8
+
+/* Command related */
+#define MMC_MAX_COMMAND_RETRY 1000
+#define MMC_RD_BLOCK_LEN 512
+#define MMC_WR_BLOCK_LEN 512
+#define MMC_R1_BLOCK_LEN_ERR (1 << 29)
+#define MMC_R1_ADDR_ERR (1 << 30)
+
+/* RCA of the card */
+#define MMC_RCA 2
+
+/* Misc card macros */
+#define MMC_BLK_SZ 512
+
+/* Clock rates */
+#define MMC_CLK_400KHZ 400000
+#define MMC_CLK_144KHZ 144000
+#define MMC_CLK_20MHZ 20000000
+#define MMC_CLK_25MHZ 25000000
+#define MMC_CLK_48MHZ 48000000
+#define MMC_CLK_50MHZ 49152000
+#define MMC_CLK_96MHZ 96000000
+#define MMC_CLK_200MHZ 200000000
+
+/* Can be used to unpack array of upto 32 bits data */
+#define UNPACK_BITS(array, start, len, size_of) \
+ ({ \
+ uint32_t indx = (start) / (size_of); \
+ uint32_t offset = (start) % (size_of); \
+ uint32_t mask = (((len)<(size_of))? 1<<(len):0) - 1; \
+ uint32_t unpck = array[indx] >> offset; \
+ uint32_t indx2 = ((start) + (len) - 1) / (size_of); \
+ if(indx2 > indx) \
+ unpck |= array[indx2] << ((size_of) - offset); \
+ unpck & mask; \
+ })
+
+/* CSD Register.
+ * Note: not all the fields have been defined here
+ */
+struct mmc_csd {
+ uint32_t cmmc_structure;
+ uint32_t spec_vers;
+ uint32_t card_cmd_class;
+ uint32_t write_blk_len;
+ uint32_t read_blk_len;
+ uint32_t r2w_factor;
+ uint32_t sector_size;
+ uint32_t c_size_mult;
+ uint32_t c_size;
+ uint32_t nsac_clk_cycle;
+ uint32_t taac_ns;
+ uint32_t tran_speed;
+ uint32_t erase_grp_size;
+ uint32_t erase_grp_mult;
+ uint32_t wp_grp_size;
+ uint32_t wp_grp_enable:1;
+ uint32_t perm_wp:1;
+ uint32_t temp_wp:1;
+ uint32_t erase_blk_len:1;
+ uint32_t read_blk_misalign:1;
+ uint32_t write_blk_misalign:1;
+ uint32_t read_blk_partial:1;
+ uint32_t write_blk_partial:1;
+};
+
+/* CID Register */
+struct mmc_cid {
+ uint32_t mid; /* 8 bit manufacturer id */
+ uint32_t oid; /* 16 bits 2 character ASCII - OEM ID */
+ uint8_t pnm[7]; /* 6 character ASCII - product name */
+ uint32_t prv; /* 8 bits - product revision */
+ uint32_t psn; /* 32 bits - product serial number */
+ uint32_t month; /* 4 bits manufacturing month */
+ uint32_t year; /* 4 bits manufacturing year */
+};
+
+/* mmc card register */
+struct mmc_card {
+ uint32_t rca; /* Relative addres of the card*/
+ uint32_t ocr; /* Operating range of the card*/
+ uint64_t capacity; /* card capacity */
+ uint32_t type; /* Type of the card */
+ uint32_t status; /* Card status */
+ uint8_t *ext_csd; /* Ext CSD for the card info */
+ uint32_t raw_csd[4]; /* Raw CSD for the card */
+ struct mmc_cid cid; /* CID structure */
+ struct mmc_csd csd; /* CSD structure */
+};
+
+/* mmc device config data */
+struct mmc_config_data {
+ uint8_t slot; /* Sdcc slot used */
+ uint32_t base; /* Based address for the sdcc */
+ uint16_t bus_width; /* Bus width used */
+ uint32_t max_clk_rate; /* Max clock rate supported */
+};
+
+/* mmc device structure */
+struct mmc_device {
+ struct sdhci_host host; /* Handle to host controller */
+ struct mmc_card card; /* Handle to mmc card */
+ struct mmc_config_data config; /* Handle for the mmc config data */
+};
+
+/*
+ * APIS exposed to block level driver
+ */
+/* API: Initialize the mmc card */
+struct mmc_device *mmc_init(struct mmc_config_data *);
+/* API: Read required number of blocks from card into destination */
+uint32_t mmc_sdhci_read(struct mmc_device *dev, void *dest, uint64_t blk_addr, uint32_t num_blocks);
+/* API: Write requried number of blocks from source to card */
+uint32_t mmc_sdhci_write(struct mmc_device *dev, void *src, uint64_t blk_addr, uint32_t num_blocks);
+#endif
diff --git a/platform/msm_shared/include/mmc_wrapper.h b/platform/msm_shared/include/mmc_wrapper.h
new file mode 100644
index 0000000..5b12990
--- /dev/null
+++ b/platform/msm_shared/include/mmc_wrapper.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MMC_WRAPPER_H__
+#define __MMC_WRAPPER_H__
+
+#include <mmc_sdhci.h>
+
+/* Wrapper APIs */
+
+struct mmc_device *get_mmc_device();
+uint32_t mmc_get_psn(void);
+
+uint32_t mmc_read(uint64_t data_addr, uint32_t *out, uint32_t data_len);
+uint32_t mmc_write(uint64_t data_addr, uint32_t data_len, void *in);
+uint32_t mmc_erase_card(uint64_t, uint64_t);
+uint64_t mmc_get_device_capacity(void);
+uint32_t mmc_erase_card(uint64_t addr, uint64_t len);
+#endif
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
new file mode 100644
index 0000000..ff61868
--- /dev/null
+++ b/platform/msm_shared/include/sdhci.h
@@ -0,0 +1,340 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_SDHCI_H_
+#define __PLATFORM_SDHCI_H_
+
+#include <reg.h>
+#include <bits.h>
+
+/*
+ * Capabilities for the host controller
+ * These values are read from the capabilities
+ * register in the controller
+ */
+struct host_caps {
+ uint32_t base_clk_rate; /* Max clock rate supported */
+ uint32_t max_blk_len; /* Max block len supported */
+ uint8_t bus_width_8bit; /* 8 Bit mode supported */
+ uint8_t adma_support; /* Adma support */
+ uint8_t voltage; /* Supported voltage */
+ uint8_t sdr_support; /* Single Data rate */
+ uint8_t ddr_support; /* Dual Data rate */
+ uint8_t sdr50_support; /* UHS mode, with 100 MHZ clock */
+};
+
+/*
+ * sdhci host structure, holding information about host
+ * controller parameters
+ */
+struct sdhci_host {
+ uint32_t base; /* Base address for the host */
+ uint32_t cur_clk_rate; /* Running clock rate */
+ struct host_caps caps; /* Host capabilities */
+};
+
+/*
+ * Data pointer to be read/written
+ */
+struct mmc_data {
+ void *data_ptr; /* Points to stream of data */
+ uint32_t num_blocks; /* num of blocks, each always of size SDHCI_MMC_BLK_SZ */
+};
+
+/*
+ * mmc command structure as per the spec
+ */
+struct mmc_command {
+ uint16_t cmd_index; /* Command index */
+ uint32_t argument; /* Command argument */
+ uint8_t data_present; /* Command has data */
+ uint8_t cmd_type; /* command type */
+ uint16_t resp_type; /* Response type of the command */
+ uint32_t resp[4]; /* 128 bit response value */
+ uint32_t trans_mode; /* Transfer mode, read/write */
+ uint32_t cmd_retry; /* Retry the command, if card is busy */
+ struct mmc_data data; /* Data pointer */
+};
+
+/*
+ * Descriptor table for adma
+ */
+struct desc_entry {
+ uint16_t tran_att; /* Attribute for transfer data */
+ uint16_t len; /* Length of data */
+ void *addr; /* Address of the data */
+};
+
+/*
+ * Command types for sdhci
+ */
+enum {
+ SDHCI_CMD_TYPE_NORMAL = 0,
+ SDHCI_CMD_TYPE_SUSPEND,
+ SDHCI_CMD_TYPE_RESUME,
+ SDHCI_CMD_TYPE_ABORT,
+} sdhci_cmd_type;
+
+/*
+ * Response type values for sdhci
+ */
+enum {
+ SDHCI_CMD_RESP_NONE = 0,
+ SDHCI_CMD_RESP_136,
+ SDHCI_CMD_RESP_48,
+ SDHCI_CMD_RESP_48_BUSY,
+} sdhci_resp_type;
+
+
+/*
+ * Helper macros for writing byte, word & long registers
+ */
+#define REG_READ8(host, a) readb(host->base + a);
+#define REG_WRITE8(host, v, a) writeb(v, (host->base + a))
+
+#define REG_READ32(host, a) readl(host->base + a)
+#define REG_WRITE32(host, v, a) writel(v, (host->base + a))
+
+#define REG_READ16(host, a) readhw(host->base + a)
+#define REG_WRITE16(host, v, a) writehw(v, (host->base + a))
+
+/*
+ * SDHCI registers, as per the host controller spec v 3.0
+ */
+#define SDHCI_ARG2_REG (0x000)
+#define SDHCI_BLKSZ_REG (0x004)
+#define SDHCI_BLK_CNT_REG (0x006)
+#define SDHCI_ARGUMENT_REG (0x008)
+#define SDHCI_TRANS_MODE_REG (0x00C)
+#define SDHCI_CMD_REG (0x00E)
+#define SDHCI_RESP_REG (0x010)
+#define SDHCI_PRESENT_STATE_REG (0x024)
+#define SDHCI_HOST_CTRL1_REG (0x028)
+#define SDHCI_PWR_CTRL_REG (0x029)
+#define SDHCI_CLK_CTRL_REG (0x02C)
+#define SDHCI_TIMEOUT_REG (0x02E)
+#define SDHCI_RESET_REG (0x02F)
+#define SDHCI_NRML_INT_STS_REG (0x030)
+#define SDHCI_ERR_INT_STS_REG (0x032)
+#define SDHCI_NRML_INT_STS_EN_REG (0x034)
+#define SDHCI_ERR_INT_STS_EN_REG (0x036)
+#define SDHCI_NRML_INT_SIG_EN_REG (0x038)
+#define SDHCI_ERR_INT_SIG_EN_REG (0x03A)
+#define SDHCI_HOST_CTRL2_REG (0x03E)
+#define SDHCI_CAPS_REG1 (0x040)
+#define SDHCI_CAPS_REG2 (0x044)
+#define SDHCI_ADM_ADDR_REG (0x058)
+
+/*
+ * Helper macros for register writes
+ */
+#define SDHCI_SOFT_RESET BIT(0)
+#define SOFT_RESET_CMD BIT(1)
+#define SOFT_RESET_DATA BIT(2)
+#define SDHCI_1_8_VOL_SET BIT(3)
+
+/*
+ * Interrupt related
+ */
+#define SDHCI_NRML_INT_STS_EN 0x000B
+#define SDHCI_ERR_INT_STS_EN 0xFFFF
+#define SDHCI_NRML_INT_SIG_EN 0x000B
+#define SDHCI_ERR_INT_SIG_EN 0xFFFF
+
+#define SDCC_HC_INT_CARD_REMOVE BIT(7)
+#define SDCC_HC_INT_CARD_INSERT BIT(6)
+
+/*
+ * HC mode enable/disable
+ */
+#define SDHCI_HC_MODE_EN BIT(0)
+#define SDHCI_HC_MODE_DIS (0 << 1)
+
+/*
+ * Clk control related
+ */
+#define SDHCI_CLK_MAX_DIV 2046
+#define SDHCI_SDCLK_FREQ_SEL 8
+#define SDHCI_SDCLK_UP_BIT_SEL 6
+#define SDHCI_SDCLK_FREQ_MASK 0xFF
+#define SDHC_SDCLK_UP_BIT_MASK 0x300
+#define SDHCI_INT_CLK_EN BIT(0)
+#define SDHCI_CLK_STABLE_MASK BIT(1)
+#define SDHCI_CLK_STABLE BIT(1)
+#define SDHCI_CLK_EN BIT(2)
+#define SDHCI_CLK_DIS (0 << 2)
+#define SDHCI_CLK_RATE_MASK 0x0000FF00
+#define SDHCI_CLK_RATE_BIT 8
+
+#define SDHCI_CMD_ACT BIT(0)
+#define SDHCI_DAT_ACT BIT(1)
+
+/*
+ * Bus voltage related macros
+ */
+#define SDHCI_BUS_VOL_SEL 1
+#define SDHCI_BUS_PWR_EN BIT(0)
+#define SDHCI_VOL_1_8 5
+#define SDHCI_VOL_3_0 6
+#define SDHCI_VOL_3_3 7
+#define SDHCI_3_3_VOL_MASK 0x01000000
+#define SDHCI_3_0_VOL_MASK 0x02000000
+#define SDHCI_1_8_VOL_MASK 0x04000000
+
+/*
+ * Bus width related macros
+ */
+#define SDHCI_8BIT_WIDTH_MASK 0x00040000
+
+#define SDHCI_BUS_WITDH_1BIT (0)
+#define SDHCI_BUS_WITDH_4BIT BIT(1)
+#define SDHCI_BUS_WITDH_8BIT BIT(5)
+
+/*
+ * Adma related macros
+ */
+#define SDHCI_BLK_LEN_MASK 0x00030000
+#define SDHCI_BLK_LEN_BIT 16
+#define SDHCI_BLK_ADMA_MASK 0x00080000
+#define SDHCI_INT_STS_TRANS_COMPLETE BIT(1)
+#define SDHCI_STATE_CMD_DAT_MASK 0x0003
+#define SDHCI_INT_STS_CMD_COMPLETE BIT(0)
+#define SDHCI_ERR_INT_STAT_MASK 0x8000
+#define SDHCI_ADMA_DESC_LINE_SZ 65536
+#define SDHCI_ADMA_MAX_TRANS_SZ (65535 * 512)
+#define SDHCI_ADMA_TRANS_VALID BIT(0)
+#define SDHCI_ADMA_TRANS_END BIT(1)
+#define SDHCI_ADMA_TRANS_DATA BIT(5)
+#define SDHCI_MMC_BLK_SZ 512
+#define SDHCI_MMC_CUR_BLK_CNT_BIT 16
+#define SDHCI_MMC_BLK_SZ_BIT 0
+#define SDHCI_TRANS_MULTI BIT(5)
+#define SDHCI_TRANS_SINGLE (0 << 5)
+#define SDHCI_BLK_CNT_EN BIT(1)
+#define SDHCI_DMA_EN BIT(0)
+#define SDHCI_AUTO_CMD23_EN BIT(3)
+#define SDHCI_ADMA_32BIT BIT(4)
+
+/*
+ * Command related macros
+ */
+#define SDHCI_CMD_RESP_TYPE_SEL_BIT 0
+#define SDHCI_CMD_CRC_CHECK_BIT 3
+#define SDHCI_CMD_IDX_CHECK_BIT 4
+#define SDHCI_CMD_DATA_PRESENT_BIT 5
+#define SDHCI_CMD_CMD_TYPE_BIT 6
+#define SDHCI_CMD_CMD_IDX_BIT 8
+#define SDHCI_CMD_TIMEOUT_MASK BIT(0)
+#define SDHCI_CMD_CRC_MASK BIT(1)
+#define SDHCI_CMD_END_BIT_MASK BIT(2)
+#define SDHCI_CMD_IDX_MASK BIT(3)
+#define SDHCI_DAT_TIMEOUT_MASK BIT(4)
+#define SDHCI_DAT_CRC_MASK BIT(5)
+#define SDHCI_DAT_END_BIT_MASK BIT(6)
+#define SDHCI_CUR_LIM_MASK BIT(7)
+#define SDHCI_AUTO_CMD12_MASK BIT(8)
+#define SDHCI_ADMA_MASK BIT(9)
+#define SDHCI_READ_MODE BIT(4)
+#define SDHCI_SWITCH_CMD 6
+#define SDHCI_CMD_TIMEOUT 0xE
+#define SDHCI_MAX_CMD_RETRY 10000
+#define SDHCI_MAX_TRANS_RETRY 100000
+
+#define SDHCI_PREP_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff))
+
+/*
+ * command response related
+ */
+#define SDHCI_RESP_LSHIFT 8
+#define SDHCI_RESP_RSHIFT 24
+
+/*
+ * Power control relatd macros
+ */
+#define SDHCI_SOFT_RESET_MASK (BIT(0) | BIT(1) | BIT(2))
+#define SDCC_HC_PWR_CTRL_INT 0xF
+#define SDCC_HC_BUS_ON BIT(0)
+#define SDCC_HC_BUS_OFF BIT(1)
+#define SDCC_HC_BUS_ON_OFF_SUCC BIT(0)
+#define SDCC_HC_IO_SIG_LOW BIT(2)
+#define SDCC_HC_IO_SIG_HIGH BIT(3)
+#define SDCC_HC_IO_SIG_SUCC BIT(2)
+
+/*
+ * Command response
+ */
+#define SDHCI_CMD_RESP_NONE 0
+#define SDHCI_CMD_RESP_R1 BIT(0)
+#define SDHCI_CMD_RESP_R1B BIT(1)
+#define SDHCI_CMD_RESP_R2 BIT(2)
+#define SDHCI_CMD_RESP_R3 BIT(3)
+#define SDHCI_CMD_RESP_R6 BIT(6)
+#define SDHCI_CMD_RESP_R7 BIT(7)
+
+/*
+ * Clock Divider values
+ */
+#define SDHCI_CLK_400KHZ 400000
+#define SDHCI_CLK_25MHZ 25000000
+#define SDHCI_CLK_50MHZ 50000000
+#define SDHCI_CLK_100MHZ 100000000
+#define SDHCI_CLK_200MHZ 200000000
+
+/* DDR mode related macros */
+#define SDHCI_DDR_MODE_EN 0x0004
+#define SDHCI_DDR_MODE_MASK BIT(2)
+
+/* HS200/SDR50 mode related macros */
+#define SDHCI_SDR50_MODE_MASK BIT(0)
+#define SDHCI_SDR50_MODE_EN 0x0002
+
+/*
+ * APIs and macros exposed for mmc/sd drivers
+ */
+#define SDHCI_MMC_WRITE 0
+#define SDHCI_MMC_READ 1
+
+#define DATA_BUS_WIDTH_1BIT 0
+#define DATA_BUS_WIDTH_4BIT 1
+#define DATA_BUS_WIDTH_8BIT 2
+#define DATA_DDR_BUS_WIDTH_4BIT 5
+#define DATA_DDR_BUS_WIDTH_8BIT 6
+
+/* API: to initialize the controller */
+void sdhci_init(struct sdhci_host *);
+/* API: Send the command & transfer data using adma */
+uint32_t sdhci_send_command(struct sdhci_host *, struct mmc_command *);
+/* API: Set the bus width for the contoller */
+uint8_t sdhci_set_bus_width(struct sdhci_host *, uint16_t);
+/* API: Clock supply for the controller */
+uint32_t sdhci_clk_supply(struct sdhci_host *, uint32_t);
+/* API: Enable DDR mode */
+void sdhci_set_ddr_mode(struct sdhci_host *);
+/* API: To enable SDR mode */
+void sdhci_set_sdr_mode(struct sdhci_host *);
+#endif
diff --git a/platform/msm_shared/mipi_dsi.c b/platform/msm_shared/mipi_dsi.c
index 055de7d..313edc4 100644
--- a/platform/msm_shared/mipi_dsi.c
+++ b/platform/msm_shared/mipi_dsi.c
@@ -712,7 +712,7 @@
writel(0x00000006, DSI_CLK_CTRL);
writel(0x0000000e, DSI_CLK_CTRL);
writel(0x0000001e, DSI_CLK_CTRL);
- writel(0x0000003e, DSI_CLK_CTRL);
+ writel(0x0000023f, DSI_CLK_CTRL);
writel(0, DSI_CTRL);
@@ -746,7 +746,7 @@
writel(vsync_width << 16 | 0, DSI_VIDEO_MODE_VSYNC_VPOS);
- writel(1, DSI_EOT_PACKET_CTRL);
+ writel(0x0, DSI_EOT_PACKET_CTRL);
writel(0x00000100, DSI_MISR_VIDEO_CTRL);
@@ -760,6 +760,7 @@
| dst_format << 4 | 0x0, DSI_VIDEO_MODE_CTRL);
}
+ writel(0x3fd08, DSI_HS_TIMER_CTRL);
writel(0x67, DSI_CAL_STRENGTH_CTRL);
writel(0x80006711, DSI_CAL_CTRL);
writel(0x00010100, DSI_MISR_VIDEO_CTRL);
diff --git a/platform/msm_shared/mmc_sdhci.c b/platform/msm_shared/mmc_sdhci.c
new file mode 100644
index 0000000..b565d9e
--- /dev/null
+++ b/platform/msm_shared/mmc_sdhci.c
@@ -0,0 +1,1315 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <debug.h>
+#include <reg.h>
+#include <mmc_sdhci.h>
+#include <sdhci.h>
+#include <partition_parser.h>
+#include <platform/iomap.h>
+#include <platform/timer.h>
+
+extern void clock_init_mmc(uint32_t);
+extern void clock_config_mmc(uint32_t, uint32_t);
+
+/* data access time unit in ns */
+static const uint32_t taac_unit[] =
+{
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* data access time value x 10 */
+static const uint32_t taac_value[] =
+{
+ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
+};
+
+/* data transfer rate in kbit/s */
+static const uint32_t xfer_rate_unit[] =
+{
+ 100, 1000, 10000, 100000, 0, 0, 0, 0
+};
+
+/* data transfer rate value x 10*/
+static const uint32_t xfer_rate_value[] =
+{
+ 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
+};
+
+/*
+ * Function: mmc decode and save csd
+ * Arg : Card structure & raw csd
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Decodes CSD response received from the card.
+ * Note that we have defined only few of the CSD elements
+ * in csd structure. We'll only decode those values.
+ */
+static uint32_t mmc_decode_and_save_csd(struct mmc_card *card)
+{
+ uint32_t mmc_sizeof = 0;
+ uint32_t mmc_unit = 0;
+ uint32_t mmc_value = 0;
+ uint32_t mmc_temp = 0;
+ uint32_t *raw_csd = card->raw_csd;
+
+ struct mmc_csd mmc_csd;
+
+ mmc_sizeof = sizeof(uint32_t) * 8;
+
+ mmc_csd.cmmc_structure = UNPACK_BITS(raw_csd, 126, 2, mmc_sizeof);
+
+ if ((card->type == MMC_TYPE_SDHC)
+ || (card->type == MMC_TYPE_STD_SD)) {
+ /* Parse CSD according to SD card spec. */
+
+ /* CSD register is little bit differnet for CSD version 2.0 High
+ * Capacity and CSD version 1.0/2.0 Standard memory cards.
+ * In Version 2.0 some of the fields have fixed values and it's
+ * not necessary for host to refer these fields in CSD sent by
+ * card
+ */
+
+ if (mmc_csd.cmmc_structure == 1) {
+ /* CSD Version 2.0 */
+ mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+ /* Fixed value is 9 = 2^9 = 512 */
+ mmc_csd.write_blk_len = 512;
+ /* Fixed value is 9 = 512 */
+ mmc_csd.read_blk_len = 512;
+ /* Fixed value: 010b */
+ mmc_csd.r2w_factor = 0x2;
+ /* Not there in version 2.0 */
+ mmc_csd.c_size_mult = 0;
+ mmc_csd.c_size = UNPACK_BITS(raw_csd, 48, 22, mmc_sizeof);
+ mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof)
+ * 100;
+
+ mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+ mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+ mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit])
+ / 10;
+
+ mmc_csd.erase_blk_len = 1;
+ mmc_csd.read_blk_misalign = 0;
+ mmc_csd.write_blk_misalign = 0;
+ mmc_csd.read_blk_partial = 0;
+ mmc_csd.write_blk_partial = 0;
+
+ mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
+ mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
+ mmc_csd.tran_speed = (xfer_rate_value[mmc_value] *
+ xfer_rate_unit[mmc_unit]) / 10;
+
+ mmc_csd.wp_grp_size = 0x0;
+ mmc_csd.wp_grp_enable = 0x0;
+ mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+ mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+ /* Calculate the card capcity */
+ card->capacity = (1 + mmc_csd.c_size) * 512 * 1024;
+ } else {
+ /* CSD Version 1.0 */
+ mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+
+ mmc_temp = UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
+ mmc_csd.write_blk_len = (mmc_temp > 8 && mmc_temp < 12) ?
+ (1 << mmc_temp) : 512;
+
+ mmc_temp = UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
+ mmc_csd.read_blk_len = (mmc_temp > 8 && mmc_temp < 12) ?
+ (1 << mmc_temp) : 512;
+
+ mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+ mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+ mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit])
+ / 10;
+
+ mmc_unit = UNPACK_BITS(raw_csd, 96, 3, mmc_sizeof);
+ mmc_value = UNPACK_BITS(raw_csd, 99, 4, mmc_sizeof);
+ mmc_csd.tran_speed = (xfer_rate_value[mmc_value] *
+ xfer_rate_unit[mmc_unit]) / 10;
+
+ mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof)
+ * 100;
+
+ mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
+ mmc_csd.sector_size = UNPACK_BITS(raw_csd, 39, 7, mmc_sizeof) + 1;
+
+ mmc_csd.erase_blk_len = UNPACK_BITS(raw_csd, 46, 1, mmc_sizeof);
+ mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
+ mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
+ mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
+ mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
+
+ mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
+ mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
+ mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 7, mmc_sizeof);
+ mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
+ mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+ mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+ /* Calculate the card capacity */
+ mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
+ card->capacity = mmc_temp * mmc_csd.read_blk_len;
+ }
+ } else {
+ /* Parse CSD according to MMC card spec. */
+ mmc_csd.spec_vers = UNPACK_BITS(raw_csd, 122, 4, mmc_sizeof);
+ mmc_csd.card_cmd_class = UNPACK_BITS(raw_csd, 84, 12, mmc_sizeof);
+ mmc_csd.write_blk_len = 1 << UNPACK_BITS(raw_csd, 22, 4, mmc_sizeof);
+ mmc_csd.read_blk_len = 1 << UNPACK_BITS(raw_csd, 80, 4, mmc_sizeof);
+ mmc_csd.r2w_factor = UNPACK_BITS(raw_csd, 26, 3, mmc_sizeof);
+ mmc_csd.c_size_mult = UNPACK_BITS(raw_csd, 47, 3, mmc_sizeof);
+ mmc_csd.c_size = UNPACK_BITS(raw_csd, 62, 12, mmc_sizeof);
+ mmc_csd.nsac_clk_cycle = UNPACK_BITS(raw_csd, 104, 8, mmc_sizeof) * 100;
+
+ mmc_unit = UNPACK_BITS(raw_csd, 112, 3, mmc_sizeof);
+ mmc_value = UNPACK_BITS(raw_csd, 115, 4, mmc_sizeof);
+ mmc_csd.taac_ns = (taac_value[mmc_value] * taac_unit[mmc_unit]) / 10;
+
+ mmc_csd.read_blk_misalign = UNPACK_BITS(raw_csd, 77, 1, mmc_sizeof);
+ mmc_csd.write_blk_misalign = UNPACK_BITS(raw_csd, 78, 1, mmc_sizeof);
+ mmc_csd.read_blk_partial = UNPACK_BITS(raw_csd, 79, 1, mmc_sizeof);
+ mmc_csd.write_blk_partial = UNPACK_BITS(raw_csd, 21, 1, mmc_sizeof);
+
+ /* Ignore -- no use of this value. */
+ mmc_csd.tran_speed = 0x00;
+
+ mmc_csd.erase_grp_size = UNPACK_BITS(raw_csd, 42, 5, mmc_sizeof);
+ mmc_csd.erase_grp_mult = UNPACK_BITS(raw_csd, 37, 5, mmc_sizeof);
+ mmc_csd.wp_grp_size = UNPACK_BITS(raw_csd, 32, 5, mmc_sizeof);
+ mmc_csd.wp_grp_enable = UNPACK_BITS(raw_csd, 31, 1, mmc_sizeof);
+ mmc_csd.perm_wp = UNPACK_BITS(raw_csd, 13, 1, mmc_sizeof);
+ mmc_csd.temp_wp = UNPACK_BITS(raw_csd, 12, 1, mmc_sizeof);
+
+ /* Calculate the card capcity */
+ if (mmc_csd.c_size != 0xFFF) {
+ /* For cards less than or equal to 2GB */
+ mmc_temp = (1 << (mmc_csd.c_size_mult + 2)) * (mmc_csd.c_size + 1);
+ card->capacity = mmc_temp * mmc_csd.read_blk_len;
+ } else {
+ /* For cards greater than 2GB, Ext CSD register's SEC_COUNT
+ * is used to calculate the size.
+ */
+ uint64_t sec_count;
+
+ sec_count = (card->ext_csd[MMC_SEC_COUNT4] << MMC_SEC_COUNT4_SHIFT)
+ | (card->ext_csd[MMC_SEC_COUNT3] << MMC_SEC_COUNT3_SHIFT)
+ | (card->ext_csd[MMC_SEC_COUNT2] << MMC_SEC_COUNT2_SHIFT)
+ | card->ext_csd[MMC_SEC_COUNT1];
+
+ card->capacity = sec_count * MMC_BLK_SZ;
+ }
+ }
+
+ /* save the information in card structure */
+ memcpy((struct mmc_csd *)&card->csd,(struct mmc_csd *)&mmc_csd,
+ sizeof(struct mmc_csd));
+
+ dprintf(SPEW, "Decoded CSD fields:\n");
+ dprintf(SPEW, "cmmc_structure: %d\n", mmc_csd.cmmc_structure);
+ dprintf(SPEW, "card_cmd_class: %x\n", mmc_csd.card_cmd_class);
+ dprintf(SPEW, "write_blk_len: %d\n", mmc_csd.write_blk_len);
+ dprintf(SPEW, "read_blk_len: %d\n", mmc_csd.read_blk_len);
+ dprintf(SPEW, "r2w_factor: %d\n", mmc_csd.r2w_factor);
+ dprintf(SPEW, "sector_size: %d\n", mmc_csd.sector_size);
+ dprintf(SPEW, "c_size_mult:%d\n", mmc_csd.c_size_mult);
+ dprintf(SPEW, "c_size: %d\n", mmc_csd.c_size);
+ dprintf(SPEW, "nsac_clk_cycle: %d\n", mmc_csd.nsac_clk_cycle);
+ dprintf(SPEW, "taac_ns: %d\n", mmc_csd.taac_ns);
+ dprintf(SPEW, "tran_speed: %d kbps\n", mmc_csd.tran_speed);
+ dprintf(SPEW, "erase_blk_len: %d\n", mmc_csd.erase_blk_len);
+ dprintf(SPEW, "read_blk_misalign: %d\n", mmc_csd.read_blk_misalign);
+ dprintf(SPEW, "write_blk_misalign: %d\n", mmc_csd.write_blk_misalign);
+ dprintf(SPEW, "read_blk_partial: %d\n", mmc_csd.read_blk_partial);
+ dprintf(SPEW, "write_blk_partial: %d\n", mmc_csd.write_blk_partial);
+ dprintf(SPEW, "Card Capacity: %llu Bytes\n", card->capacity);
+
+ return 0;
+}
+
+/*
+ * Function: mmc decode & save cid
+ * Arg : card structure & raw cid
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Decode CID sent by the card.
+ */
+static uint32_t mmc_decode_and_save_cid(struct mmc_card *card,
+ uint32_t *raw_cid)
+{
+ struct mmc_cid mmc_cid;
+ uint32_t mmc_sizeof = 0;
+ int i = 0;
+
+ if (!raw_cid) {
+ return 1;
+ }
+
+ mmc_sizeof = sizeof(uint32_t) * 8;
+
+ if ((card->type == MMC_TYPE_SDHC) ||
+ (card->type == MMC_TYPE_STD_SD)) {
+ mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
+ mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
+
+ for (i = 0; i < 5; i++) {
+ mmc_cid.pnm[i] = (uint8_t)UNPACK_BITS(raw_cid,
+ (104 - 8 * (i + 1)),
+ 8,
+ mmc_sizeof);
+ }
+ mmc_cid.pnm[5] = 0;
+ mmc_cid.pnm[6] = 0;
+
+ mmc_cid.prv = UNPACK_BITS(raw_cid, 56, 8, mmc_sizeof);
+ mmc_cid.psn = UNPACK_BITS(raw_cid, 24, 31, mmc_sizeof);
+ mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
+ mmc_cid.year = UNPACK_BITS(raw_cid, 12, 8, mmc_sizeof);
+ mmc_cid.year += 2000;
+ } else {
+ mmc_cid.mid = UNPACK_BITS(raw_cid, 120, 8, mmc_sizeof);
+ mmc_cid.oid = UNPACK_BITS(raw_cid, 104, 16, mmc_sizeof);
+
+ for (i = 0; i < 6; i++) {
+ mmc_cid.pnm[i] = (uint8_t)UNPACK_BITS(raw_cid, (104 - 8 * (i + 1)),
+ 8, mmc_sizeof);
+ }
+ mmc_cid.pnm[6] = 0;
+
+ mmc_cid.prv = UNPACK_BITS(raw_cid, 48, 8, mmc_sizeof);
+ mmc_cid.psn = UNPACK_BITS(raw_cid, 16, 31, mmc_sizeof);
+ mmc_cid.month = UNPACK_BITS(raw_cid, 8, 4, mmc_sizeof);
+ mmc_cid.year = UNPACK_BITS(raw_cid, 12, 4, mmc_sizeof);
+ mmc_cid.year += 1997;
+ }
+
+ /* save it in card database */
+ memcpy((struct mmc_cid *)&card->cid,
+ (struct mmc_cid *)&mmc_cid, sizeof(struct mmc_cid));
+
+ dprintf(SPEW, "Decoded CID fields:\n");
+ dprintf(SPEW, "Manufacturer ID: %x\n", mmc_cid.mid);
+ dprintf(SPEW, "OEM ID: 0x%x\n", mmc_cid.oid);
+ dprintf(SPEW, "Product Name: %s\n", mmc_cid.pnm);
+ dprintf(SPEW, "Product revision: %d.%d\n", (mmc_cid.prv >> 4),
+ (mmc_cid.prv & 0xF));
+ dprintf(SPEW, "Product serial number: %X\n", mmc_cid.psn);
+ dprintf(SPEW, "Manufacturing date: %d %d\n", mmc_cid.month, mmc_cid.year);
+
+ return 0;
+}
+
+/*
+ * Function: mmc reset cards
+ * Arg : host structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Reset all the cards to idle condition (CMD 0)
+ */
+static uint8_t mmc_reset_card(struct sdhci_host *host)
+{
+ struct mmc_command cmd;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.cmd_index = CMD0_GO_IDLE_STATE;
+ cmd.argument = 0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_NONE;
+
+ /* send command */
+ return sdhci_send_command(host, &cmd);
+}
+
+/*
+ * Function: mmc operations command
+ * Arg : host & card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Send CMD1 to know whether the card supports host VDD profile or not.
+ */
+static uint32_t mmc_send_op_cond(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_resp = 0;
+ uint32_t mmc_ret = 0;
+ uint32_t mmc_retry = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD1 format:
+ * [31] Busy bit
+ * [30:29] Access mode
+ * [28:24] reserved
+ * [23:15] 2.7-3.6
+ * [14:8] 2.0-2.6
+ * [7] 1.7-1.95
+ * [6:0] reserved
+ */
+
+ cmd.cmd_index = CMD1_SEND_OP_COND;
+ cmd.argument = card->ocr;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R3;
+
+ do {
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /* Command returned success, now it's time to examine response */
+ mmc_resp = cmd.resp[0];
+
+ /* Check the response for busy status */
+ if (!(mmc_resp & MMC_OCR_BUSY)) {
+ mmc_retry++;
+ mdelay(1);
+ continue;
+ } else
+ break;
+ } while (mmc_retry < MMC_MAX_COMMAND_RETRY);
+
+ /* If we reached here after max retries, we failed to get OCR */
+ if (mmc_retry == MMC_MAX_COMMAND_RETRY && !(mmc_resp & MMC_OCR_BUSY)) {
+ dprintf(CRITICAL, "Card has busy status set. Init did not complete\n");
+ return 1;
+ }
+
+ /* Response contains card's ocr. Update card's information */
+ card->ocr = mmc_resp;
+
+ if (mmc_resp & MMC_OCR_SEC_MODE)
+ card->type = MMC_TYPE_MMCHC;
+ else
+ card->type = MMC_TYPE_STD_MMC;
+
+ return 0;
+}
+
+/*
+ * Function: mmc send cid
+ * Arg : host & card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Request any card to send its uniquie card identification
+ * (CID) number (CMD2).
+ */
+static uint32_t mmc_all_send_cid(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD2 Format:
+ * [31:0] stuff bits
+ */
+ cmd.cmd_index = CMD2_ALL_SEND_CID;
+ cmd.argument = 0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R2;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret) {
+ return mmc_ret;
+ }
+
+ /* Response contains card's 128 bits CID register */
+ mmc_ret = mmc_decode_and_save_cid(card, cmd.resp);
+ if (mmc_ret) {
+ return mmc_ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: mmc send relative address
+ * Arg : host & card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Ask card to send it's relative card address (RCA).
+ * This RCA number is shorter than CID and is used by
+ * the host to address the card in future (CMD3)
+ */
+static uint32_t mmc_send_relative_address(struct sdhci_host *host,
+ struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD3 Format:
+ * [31:0] stuff bits
+ */
+ if (card->type == MMC_TYPE_SDHC ||
+ card->type == MMC_TYPE_STD_SD) {
+ cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
+ cmd.argument = 0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R6;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /* For sD, card will send RCA. Store it */
+ card->rca = (cmd.resp[0] >> 16);
+ } else {
+ cmd.cmd_index = CMD3_SEND_RELATIVE_ADDR;
+ cmd.argument = (MMC_RCA << 16);
+ card->rca = (cmd.argument >> 16);
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R6;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: mmc send csd
+ * Arg : host, card structure & o/p arg to store csd
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Requests card to send it's CSD register's contents. (CMD9)
+ */
+static uint32_t mmc_send_csd(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_arg = 0;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD9 Format:
+ * [31:16] RCA
+ * [15:0] stuff bits
+ */
+ mmc_arg |= card->rca << 16;
+
+ cmd.cmd_index = CMD9_SEND_CSD;
+ cmd.argument = mmc_arg;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R2;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /* response contains the card csd */
+ memcpy(card->raw_csd, cmd.resp, sizeof(cmd.resp));
+
+ return 0;
+}
+
+/*
+ * Function: mmc select card
+ * Arg : host, card structure & RCA
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Selects a card by sending CMD7 to the card with its RCA.
+ * If RCA field is set as 0 ( or any other address ),
+ * the card will be de-selected. (CMD7)
+ */
+static uint32_t mmc_select_card(struct sdhci_host *host, struct mmc_card *card,
+ uint32_t rca)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_arg = 0;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD7 Format:
+ * [31:16] RCA
+ * [15:0] stuff bits
+ */
+ mmc_arg |= rca << 16;
+
+ cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
+ cmd.argument = mmc_arg;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+
+ /* If we are deselecting card, we do not get response */
+ if (rca == card->rca && rca) {
+ if (card->type == MMC_TYPE_SDHC ||
+ card->type == MMC_TYPE_STD_SD)
+ cmd.resp_type = SDHCI_CMD_RESP_R1B;
+ else
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ } else
+ cmd.resp_type = SDHCI_CMD_RESP_NONE;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ return 0;
+}
+
+/*
+ * Function: mmc set block len
+ * Arg : host, card structure & block length
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Send command to set block length.
+ */
+static uint32_t mmc_set_block_len(struct sdhci_host *host,
+ struct mmc_card *card,
+ uint32_t block_len)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD16 Format:
+ * [31:0] block length
+ */
+
+ cmd.cmd_index = CMD16_SET_BLOCKLEN;
+ cmd.argument = block_len;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /*
+ * If blocklength is larger than 512 bytes,
+ * the card sets BLOCK_LEN_ERROR bit.
+ */
+ if (cmd.resp[0] & MMC_R1_BLOCK_LEN_ERR) {
+ dprintf(CRITICAL, "The block length is not supported by the card\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: mmc get card status
+ * Arg : host, card structure & o/p argument card status
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Get the current status of the card
+ */
+static uint32_t mmc_get_card_status(struct sdhci_host *host,
+ struct mmc_card *card, uint32_t *status)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD13 Format:
+ * [31:16] RCA
+ * [15:0] stuff bits
+ */
+ cmd.cmd_index = CMD13_SEND_STATUS;
+ cmd.argument = card->rca << 16;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /* Checking ADDR_OUT_OF_RANGE error in CMD13 response */
+ if ((cmd.resp[0] >> 31) & 0x01)
+ return 1;
+
+ *status = cmd.resp[0];
+ return 0;
+}
+
+/*
+ * Function: mmc get ext csd
+ * Arg : host, card structure & array to hold ext attributes
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Send ext csd command & get the card attributes
+ */
+static uint32_t mmc_get_ext_csd(struct sdhci_host *host, struct mmc_card *card)
+{
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+
+ card->ext_csd = memalign(CACHE_LINE, ROUNDUP(512, CACHE_LINE));
+
+ ASSERT(card->ext_csd);
+
+ memset(card->ext_csd, 0, sizeof(card->ext_csd));
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD8 */
+ cmd.cmd_index = CMD8_SEND_EXT_CSD;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.data.data_ptr = card->ext_csd;
+ cmd.data.num_blocks = 1;
+ cmd.data_present = 0x1;
+ cmd.trans_mode = SDHCI_MMC_READ;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ return mmc_ret;
+}
+
+/*
+ * Function: mmc switch command
+ * Arg : Host, card structure, access mode, index & value to be set
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Send switch command to the card to set the ext attribute @ index
+ */
+static uint32_t mmc_switch_cmd(struct sdhci_host *host, struct mmc_card *card,
+ uint32_t access, uint32_t index, uint32_t value)
+{
+
+ struct mmc_command cmd;
+ uint32_t mmc_ret = 0;
+ uint32_t mmc_status;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD6 Format:
+ * [31:26] set to 0
+ * [25:24] access
+ * [23:16] index
+ * [15:8] value
+ * [7:3] set to 0
+ * [2:0] cmd set
+ */
+ cmd.cmd_index = CMD6_SWITCH_FUNC;
+ cmd.argument |= (access << 24);
+ cmd.argument |= (index << 16);
+ cmd.argument |= (value << 8);
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1B;
+
+ mmc_ret = sdhci_send_command(host, &cmd);
+ if (mmc_ret) {
+ dprintf(CRITICAL, "CMD6 send failed\n");
+ return mmc_ret;
+ }
+
+ /* Check if the card completed the switch command processing */
+ mmc_ret = mmc_get_card_status(host, card, &mmc_status);
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Get card status failed\n");
+ return mmc_ret;
+ }
+
+ if (MMC_CARD_STATUS(mmc_status) != MMC_TRAN_STATE) {
+ dprintf(CRITICAL, "Switch cmd failed. Card not in tran state\n");
+ mmc_ret = 1;
+ }
+
+ if (mmc_status & MMC_SWITCH_FUNC_ERR_FLAG) {
+ dprintf(CRITICAL, "Switch cmd failed. Switch Error.\n");
+ mmc_ret = 1;
+ }
+
+ return mmc_ret;
+}
+
+/*
+ * Function: mmc set bus width
+ * Arg : Host, card structure & width
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Send switch command to set bus width
+ */
+static uint32_t mmc_set_bus_width(struct sdhci_host *host,
+ struct mmc_card *card,
+ uint32_t width)
+{
+ uint32_t mmc_ret = 0;
+
+ mmc_ret = mmc_switch_cmd(host, card, MMC_ACCESS_WRITE,
+ MMC_EXT_MMC_BUS_WIDTH, width);
+
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Switch cmd failed\n");
+ return mmc_ret;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function: mmc card supports ddr mode
+ * Arg : None
+ * Return : 1 if DDR mode is supported, 0 otherwise
+ * Flow : Check the ext csd attributes of the card
+ */
+static uint8_t mmc_card_supports_hs200_mode(struct mmc_card *card)
+{
+ if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_HS200_MODE)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Function: mmc card supports ddr mode
+ * Arg : None
+ * Return : 1 if DDR mode is supported, 0 otherwise
+ * Flow : Check the ext csd attributes of the card
+ */
+static uint8_t mmc_card_supports_ddr_mode(struct mmc_card *card)
+{
+ if (card->ext_csd[MMC_DEVICE_TYPE] & MMC_HS_DDR_MODE)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Function : Enable HS200 mode
+ * Arg : Host, card structure and bus width
+ * Return : 0 on Success, 1 on Failure
+ * Flow :
+ * - Set the bus width to 4/8 bit SDR as supported by the target & host
+ * - Set the HS_TIMING on ext_csd 185 for the card
+ */
+static uint32_t mmc_set_hs200_mode(struct sdhci_host *host,
+ struct mmc_card *card, uint32_t width)
+{
+ uint32_t mmc_ret = 0;
+
+ /* Set 4/8 bit SDR bus width */
+ mmc_ret = mmc_set_bus_width(host, card, width);
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_ret;
+ }
+
+ /* Setting HS200 in HS_TIMING using EXT_CSD (CMD6) */
+ mmc_ret = mmc_switch_cmd(host, card, MMC_ACCESS_WRITE, MMC_EXT_MMC_HS_TIMING, MMC_HS200_TIMING);
+
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Switch cmd returned failure %d\n", __LINE__);
+ return mmc_ret;
+ }
+
+ /* Enable hs200 mode in controller */
+ sdhci_set_sdr_mode(host);
+
+ return mmc_ret;
+}
+
+/*
+ * Function: mmc set ddr mode
+ * Arg : Host & card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Set bus width for ddr mode & set controller in DDR mode
+*/
+static uint8_t mmc_set_ddr_mode(struct sdhci_host *host, struct mmc_card *card)
+{
+ uint8_t mmc_ret = 0;
+
+ /* Set width for 8 bit DDR mode by default */
+ mmc_ret = mmc_set_bus_width(host, card, DATA_DDR_BUS_WIDTH_8BIT);
+
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_ret;
+ }
+
+ sdhci_set_ddr_mode(host);
+
+ return 0;
+}
+
+/*
+ * Function: mmc set high speed interface
+ * Arg : Host & card structure
+ * Return : None
+ * Flow : Sets the sdcc clock & clock divider in the host controller
+ * Adjust the interface speed to optimal speed
+ */
+static uint32_t mmc_set_hs_interface(struct sdhci_host *host,
+ struct mmc_card *card)
+{
+ uint32_t mmc_ret = 0;
+
+ /* Setting HS_TIMING in EXT_CSD (CMD6) */
+ mmc_ret = mmc_switch_cmd(host, card, MMC_ACCESS_WRITE,
+ MMC_EXT_MMC_HS_TIMING, MMC_HS_TIMING);
+
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Switch cmd returned failure %d\n", __LINE__);
+ return mmc_ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: mmc_host_init
+ * Arg : mmc device structure
+ * Return : 0 on success, 1 on Failure
+ * Flow : Initialize the host contoller
+ * Set the clock rate to 400 KHZ for init
+ */
+static uint8_t mmc_host_init(struct mmc_device *dev)
+{
+ uint8_t mmc_ret = 0;
+
+ struct sdhci_host *host;
+ struct mmc_config_data *cfg;
+
+ host = &dev->host;
+ cfg = &dev->config;
+
+ /*
+ * Initialize the controller, read the host capabilities
+ * set power on mode
+ */
+ sdhci_init(host);
+
+ /* Initialize any clocks needed for SDC controller */
+ clock_init_mmc(cfg->slot);
+
+ /* Setup initial freq to 400KHz */
+ clock_config_mmc(cfg->slot, cfg->max_clk_rate);
+
+ mmc_ret = sdhci_clk_supply(host, SDHCI_CLK_400KHZ);
+
+ return mmc_ret;
+}
+
+/*
+ * Function: mmc identify card
+ * Arg : host & card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Performs card identification process:
+ * 1. Get card's unique identification number (CID)
+ * 2. Get(for sd)/set (for mmc) relative card address (RCA)
+ * 3. Select the card to put it in TRAN state
+ */
+static uint32_t mmc_identify_card(struct sdhci_host *host, struct mmc_card *card)
+{
+ uint32_t mmc_return = 0;
+ uint32_t raw_csd[4];
+
+ /* Ask card to send its unique card identification (CID) number (CMD2) */
+ mmc_return = mmc_all_send_cid(host, card);
+ if (mmc_return) {
+ dprintf(CRITICAL,"Failure getting card's CID number!\n");
+ return mmc_return;
+ }
+
+ /* Ask card to send a relative card address (RCA) (CMD3) */
+ mmc_return = mmc_send_relative_address(host, card);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure getting card's RCA!\n");
+ return mmc_return;
+ }
+
+ /* Get card's CSD register (CMD9) */
+ mmc_return = mmc_send_csd(host, card);
+ if (mmc_return) {
+ dprintf(CRITICAL,"Failure getting card's CSD information!\n");
+ return mmc_return;
+ }
+
+ /* Select the card (CMD7) */
+ mmc_return = mmc_select_card(host, card, card->rca);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure selecting the Card with RCA: %x\n",card->rca);
+ return mmc_return;
+ }
+
+ /* Set the card status as active */
+ card->status = MMC_STATUS_ACTIVE;
+
+ return 0;
+}
+
+/*
+ * Function: mmc_reset_card_and_send_op
+ * Arg : Host & Card structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Routine to initialize MMC card. It resets a card to idle state,
+ * verify operating voltage and set the card in ready state.
+ */
+static uint32_t mmc_reset_card_and_send_op(struct sdhci_host *host, struct mmc_card *card)
+{
+ uint32_t mmc_return = 0;
+
+ /* 1. Card Reset - CMD0 */
+ mmc_return = mmc_reset_card(host);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure resetting MMC cards!\n");
+ return mmc_return;
+ }
+
+ /* 2. Card Initialization process */
+
+ /*
+ * Send CMD1 to identify and reject cards that do not match host's VDD range
+ * profile. Cards sends its OCR register in response.
+ */
+ mmc_return = mmc_send_op_cond(host, card);
+
+ /* OCR is not received, init could not complete */
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure getting OCR response from MMC Card\n");
+ return mmc_return;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: mmc_init_card
+ * Arg : mmc device structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow : Performs initialization and identification of eMMC cards connected
+ * to the host.
+ */
+
+static uint32_t mmc_card_init(struct mmc_device *dev)
+{
+ uint32_t mmc_return = 0;
+ uint32_t status;
+ uint8_t bus_width = 0;
+
+ struct sdhci_host *host;
+ struct mmc_card *card;
+ struct mmc_config_data *cfg;
+
+ host = &dev->host;
+ card = &dev->card;
+ cfg = &dev->config;
+
+ /* Initialize MMC card structure */
+ card->status = MMC_STATUS_INACTIVE;
+
+ /* TODO: Get the OCR params from target */
+ card->ocr = MMC_OCR_27_36 | MMC_OCR_SEC_MODE;
+
+ /* Reset the card & get the OCR */
+ mmc_return = mmc_reset_card_and_send_op(host, card);
+ if (mmc_return)
+ return mmc_return;
+
+ /* Identify (CMD2, CMD3 & CMD9) and select the card (CMD7) */
+ mmc_return = mmc_identify_card(host, card);
+ if (mmc_return)
+ return mmc_return;
+
+ /* set interface speed */
+ mmc_return = mmc_set_hs_interface(host, card);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Error adjusting interface speed!\n");
+ return mmc_return;
+ }
+
+ /* Set the sdcc clock to 50 MHZ */
+ sdhci_clk_supply(host, SDHCI_CLK_50MHZ);
+
+ /* Now get the extended CSD for the card */
+ if ((card->type == MMC_TYPE_STD_MMC) ||
+ (card->type == MMC_TYPE_MMCHC)) {
+ /* For MMC cards, also get the extended csd */
+ mmc_return = mmc_get_ext_csd(host, card);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure getting card's ExtCSD information!\n");
+ return mmc_return;
+ }
+ }
+
+ /* Decode and save the CSD register */
+ mmc_return = mmc_decode_and_save_csd(card);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure decoding card's CSD information!\n");
+ return mmc_return;
+ }
+
+
+ /* Set the bus width based on host, target capbilities */
+ if (cfg->bus_width == DATA_BUS_WIDTH_8BIT && host->caps.bus_width_8bit)
+ bus_width = DATA_BUS_WIDTH_8BIT;
+ /*
+ * Host contoller by default supports 4 bit & 1 bit mode.
+ * No need to check for host support here
+ */
+ else if (cfg->bus_width == DATA_BUS_WIDTH_4BIT)
+ bus_width = DATA_BUS_WIDTH_4BIT;
+ else
+ bus_width = DATA_BUS_WIDTH_1BIT;
+
+ /* Set 4/8 bit SDR bus width in controller */
+ mmc_return = sdhci_set_bus_width(host, bus_width);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failed to set bus width for host controller\n");
+ return 1;
+ }
+
+ /* Enable high speed mode in the follwing order:
+ * 1. HS200 mode if supported by host & card
+ * 2. DDR mode host, if supported by host & card
+ * 3. Use normal speed mode with supported bus width
+ */
+ if (mmc_card_supports_hs200_mode(card) && host->caps.sdr50_support) {
+ mmc_return = mmc_set_hs200_mode(host, card, bus_width);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set HS200 mode for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ } else if (mmc_card_supports_ddr_mode(card) && host->caps.ddr_support) {
+ mmc_return = mmc_set_ddr_mode(host, card);
+
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set DDR mode for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ } else {
+ /* Set 4/8 bit bus width for the card */
+ mmc_return = mmc_set_bus_width(host, card, bus_width);
+ if (mmc_return) {
+ dprintf(CRITICAL, "Failure to set wide bus for Card(RCA:%x)\n",
+ card->rca);
+ return mmc_return;
+ }
+ }
+
+
+ /* Verify TRAN state after changing speed and bus width */
+ mmc_return = mmc_get_card_status(host, card, &status);
+ if (mmc_return)
+ return mmc_return;
+
+ if (MMC_CARD_STATUS(status) != MMC_TRAN_STATE)
+ mmc_return = 1;
+
+ return mmc_return;
+}
+
+/*
+ * Function: mmc display csd
+ * Arg : None
+ * Return : None
+ * Flow : Displays the csd information
+ */
+static void mmc_display_csd(struct mmc_card *card)
+{
+ dprintf(SPEW, "erase_grpsize: %d\n", card->csd.erase_grp_size);
+ dprintf(SPEW, "erase_grpmult: %d\n", card->csd.erase_grp_mult);
+ dprintf(SPEW, "wp_grpsize: %d\n", card->csd.wp_grp_size);
+ dprintf(SPEW, "wp_grpen: %d\n", card->csd.wp_grp_enable);
+ dprintf(SPEW, "perm_wp: %d\n", card->csd.perm_wp);
+ dprintf(SPEW, "temp_wp: %d\n", card->csd.temp_wp);
+}
+
+/*
+ * Function: mmc_init
+ * Arg : MMC configuration data
+ * Return : Pointer to mmc device
+ * Flow : Entry point to MMC boot process
+ * Initialize the sd host controller
+ * Initialize the mmc card
+ * Set the clock & high speed mode
+ */
+struct mmc_device *mmc_init(struct mmc_config_data *data)
+{
+ uint8_t mmc_ret = 0;
+ struct mmc_device *dev;
+
+ dev = (struct mmc_device *) malloc (sizeof(struct mmc_device));
+
+ if (!dev) {
+ dprintf(CRITICAL, "Error allocating mmc device\n");
+ return NULL;
+ }
+
+ ASSERT(data);
+
+ memcpy((void*)&dev->config, (void*)data, sizeof(struct mmc_config_data));
+
+ memset((struct mmc_card *)&dev->card, 0, sizeof(struct mmc_card));
+
+ dev->host.base = data->base;
+
+ /* Initialize the host & clock */
+ dprintf(SPEW, " Initializing MMC host data structure and clock!\n");
+
+ mmc_ret = mmc_host_init(dev);
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Error Initializing MMC host : %u\n", mmc_ret);
+ return NULL;
+ }
+
+ /* Initialize and identify cards connected to host */
+ mmc_ret = mmc_card_init(dev);
+ if (mmc_ret) {
+ dprintf(CRITICAL, "Failed detecting MMC/SDC @ slot%d\n",
+ dev->config.slot);
+ return NULL;
+ }
+
+ dprintf(INFO, "Done initialization of the card\n");
+
+ mmc_display_csd(&dev->card);
+
+ return dev;
+}
+
+/*
+ * Function: mmc sdhci read
+ * Arg : mmc device structure, block address, number of blocks & destination
+ * Return : 0 on Success, non zero on success
+ * Flow : Fill in the command structure & send the command
+ */
+uint32_t mmc_sdhci_read(struct mmc_device *dev, void *dest,
+ uint64_t blk_addr, uint32_t num_blocks)
+{
+ uint32_t mmc_ret = 0;
+ struct mmc_command cmd;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD17/18 Format:
+ * [31:0] Data Address
+ */
+ if (num_blocks == 1)
+ cmd.cmd_index = CMD17_READ_SINGLE_BLOCK;
+ else
+ cmd.cmd_index = CMD18_READ_MULTIPLE_BLOCK;
+
+ cmd.argument = blk_addr;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.trans_mode = SDHCI_MMC_READ;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = dest;
+ cmd.data.num_blocks = num_blocks;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(&dev->host, &cmd);
+ if (mmc_ret) {
+ return mmc_ret;
+ }
+
+ /* Response contains 32 bit Card status. Here we'll check
+ BLOCK_LEN_ERROR and ADDRESS_ERROR */
+ if (cmd.resp[0] & MMC_R1_BLOCK_LEN_ERR) {
+ dprintf(CRITICAL, "The transferred bytes does not match the block length\n");
+ return 1;
+ }
+
+ /* Misaligned address not matching block length */
+ if (cmd.resp[0] & MMC_R1_ADDR_ERR) {
+ dprintf(CRITICAL, "The misaligned address did not match the block length used\n");
+ return 1;
+ }
+
+ if (MMC_CARD_STATUS(cmd.resp[0]) != MMC_TRAN_STATE) {
+ dprintf(CRITICAL, "MMC read failed, card is not in TRAN state\n");
+ return 1;
+ }
+
+ return mmc_ret;
+}
+
+/*
+ * Function: mmc sdhci write
+ * Arg : mmc device structure, block address, number of blocks & source
+ * Return : 0 on Success, non zero on success
+ * Flow : Fill in the command structure & send the command
+ */
+uint32_t mmc_sdhci_write(struct mmc_device *dev, void *src,
+ uint64_t blk_addr, uint32_t num_blocks)
+{
+ uint32_t mmc_ret = 0;
+ struct mmc_command cmd;
+
+ memset((struct mmc_command *)&cmd, 0, sizeof(struct mmc_command));
+
+ /* CMD24/25 Format:
+ * [31:0] Data Address
+ */
+
+ if (num_blocks == 1)
+ cmd.cmd_index = CMD24_WRITE_SINGLE_BLOCK;
+ else
+ cmd.cmd_index = CMD25_WRITE_MULTIPLE_BLOCK;
+
+ cmd.argument = blk_addr;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.trans_mode = SDHCI_MMC_WRITE;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = src;
+ cmd.data.num_blocks = num_blocks;
+
+ /* send command */
+ mmc_ret = sdhci_send_command(&dev->host, &cmd);
+ if (mmc_ret)
+ return mmc_ret;
+
+ /* Response contains 32 bit Card status. Here we'll check
+ BLOCK_LEN_ERROR and ADDRESS_ERROR */
+ if (cmd.resp[0] & MMC_R1_BLOCK_LEN_ERR) {
+ dprintf(CRITICAL, "The transferred bytes does not match the block length\n");
+ return 1;
+ }
+
+ /* Misaligned address not matching block length */
+ if (cmd.resp[0] & MMC_R1_ADDR_ERR) {
+ dprintf(CRITICAL, "The misaligned address did not match the block length used\n");
+ return 1;
+ }
+
+ if (MMC_CARD_STATUS(cmd.resp[0]) != MMC_TRAN_STATE) {
+ dprintf(CRITICAL, "MMC read failed, card is not in TRAN state\n");
+ return 1;
+ }
+
+ return mmc_ret;
+}
diff --git a/platform/msm_shared/mmc_wrapper.c b/platform/msm_shared/mmc_wrapper.c
new file mode 100644
index 0000000..c56a61e
--- /dev/null
+++ b/platform/msm_shared/mmc_wrapper.c
@@ -0,0 +1,171 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <mmc_sdhci.h>
+#include <mmc_wrapper.h>
+#include <sdhci.h>
+#include <target.h>
+
+/*
+ * Function: get mmc card
+ * Arg : None
+ * Return : Pointer to mmc card structure
+ * Flow : Get the card pointer from the device structure
+ */
+static struct mmc_card *get_mmc_card()
+{
+ struct mmc_device *dev;
+ struct mmc_card *card;
+
+ dev = target_mmc_device();
+ card = &dev->card;
+
+ return card;
+}
+
+/*
+ * Function: mmc_write
+ * Arg : Data address on card, data length, i/p buffer
+ * Return : 0 on Success, non zero on failure
+ * Flow : Write the data from in to the card
+ */
+uint32_t mmc_write(uint64_t data_addr, uint32_t data_len, void *in)
+{
+ int val = 0;
+ uint32_t write_size = SDHCI_ADMA_MAX_TRANS_SZ;
+ void *sptr = in;
+ struct mmc_device *dev;
+
+ dev = target_mmc_device();
+
+ ASSERT(!(data_addr % MMC_BLK_SZ));
+
+ if (data_len % MMC_BLK_SZ)
+ data_len = ROUNDUP(data_len, MMC_BLK_SZ);
+
+ /* TODO: This function is aware of max data that can be
+ * tranferred using sdhci adma mode, need to have a cleaner
+ * implementation to keep this function independent of sdhci
+ * limitations
+ */
+ while (data_len > write_size) {
+ val = mmc_sdhci_write(dev, sptr, (data_addr / MMC_BLK_SZ), (write_size / MMC_BLK_SZ));
+ sptr += write_size;
+ data_addr += write_size;
+ data_len -= write_size;
+ }
+
+ if (data_len)
+ val = mmc_sdhci_write(dev, sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+
+ return val;
+}
+
+/*
+ * Function: mmc_read
+ * Arg : Data address on card, o/p buffer & data length
+ * Return : 0 on Success, non zero on failure
+ * Flow : Read data from the card to out
+ */
+uint32_t mmc_read(uint64_t data_addr, uint32_t *out, uint32_t data_len)
+{
+ uint32_t ret = 0;
+ uint32_t read_size = SDHCI_ADMA_MAX_TRANS_SZ;
+ struct mmc_device *dev;
+ void *sptr = out;
+
+ ASSERT(!(data_addr % MMC_BLK_SZ));
+ ASSERT(!(data_len % MMC_BLK_SZ));
+
+ dev = target_mmc_device();
+
+ /* TODO: This function is aware of max data that can be
+ * tranferred using sdhci adma mode, need to have a cleaner
+ * implementation to keep this function independent of sdhci
+ * limitations
+ */
+ while (data_len > read_size) {
+ ret = mmc_sdhci_read(dev, sptr, (data_addr / MMC_BLK_SZ), (read_size / MMC_BLK_SZ));
+ sptr += read_size;
+ data_addr += read_size;
+ data_len -= read_size;
+ }
+
+ if (data_len)
+ ret = mmc_sdhci_read(dev, sptr, (data_addr / MMC_BLK_SZ), (data_len / MMC_BLK_SZ));
+
+ return ret;
+}
+
+/*
+ * Function: mmc erase card
+ * Arg : Block address & length
+ * Return : Returns 0
+ * Flow : This is dummy API for backward compatibility
+ * erase is not supported for sdhci
+ */
+uint32_t mmc_erase_card(uint64_t addr, uint64_t len)
+{
+ /* TODO: Right now with sdhci erase function
+ * is not implemented, need to be added
+ */
+ return 0;
+}
+
+/*
+ * Function: mmc get psn
+ * Arg : None
+ * Return : Returns the product serial number
+ * Flow : Get the PSN from card
+ */
+uint32_t mmc_get_psn(void)
+{
+ struct mmc_card *card;
+
+ card = get_mmc_card();
+
+ return card->cid.psn;
+}
+
+/*
+ * Function: mmc get capacity
+ * Arg : None
+ * Return : Returns the density of the emmc card
+ * Flow : Get the density from card
+ */
+uint64_t mmc_get_device_capacity()
+{
+ struct mmc_card *card;
+
+ card = get_mmc_card();
+
+ return card->capacity;
+}
+
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 1045240..5d343c5 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -13,9 +13,18 @@
$(LOCAL_DIR)/hsusb.o \
$(LOCAL_DIR)/jtag_hook.o \
$(LOCAL_DIR)/jtag.o \
- $(LOCAL_DIR)/mmc.o \
$(LOCAL_DIR)/partition_parser.o
+ifeq ($(ENABLE_SDHCI_SUPPORT),1)
+OBJS += \
+ $(LOCAL_DIR)/sdhci.o \
+ $(LOCAL_DIR)/mmc_sdhci.o \
+ $(LOCAL_DIR)/mmc_wrapper.o
+else
+OBJS += \
+ $(LOCAL_DIR)/mmc.o
+endif
+
ifeq ($(PLATFORM),msm8x60)
OBJS += $(LOCAL_DIR)/mipi_dsi.o \
$(LOCAL_DIR)/i2c_qup.o \
@@ -84,7 +93,9 @@
$(LOCAL_DIR)/crypto_hash.o \
$(LOCAL_DIR)/crypto5_eng.o \
$(LOCAL_DIR)/crypto5_wrapper.o \
- $(LOCAL_DIR)/i2c_qup.o
+ $(LOCAL_DIR)/i2c_qup.o \
+ $(LOCAL_DIR)/gpio.o \
+ $(LOCAL_DIR)/dload_util.o
endif
ifeq ($(PLATFORM),msm8226)
@@ -105,7 +116,9 @@
$(LOCAL_DIR)/crypto_hash.o \
$(LOCAL_DIR)/crypto5_eng.o \
$(LOCAL_DIR)/crypto5_wrapper.o \
- $(LOCAL_DIR)/dev_tree.o
+ $(LOCAL_DIR)/dev_tree.o \
+ $(LOCAL_DIR)/gpio.o \
+ $(LOCAL_DIR)/dload_util.o
endif
ifeq ($(PLATFORM),msm8610)
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
new file mode 100644
index 0000000..dac6fdc
--- /dev/null
+++ b/platform/msm_shared/sdhci.c
@@ -0,0 +1,835 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <platform/iomap.h>
+#include <platform/irqs.h>
+#include <platform/interrupts.h>
+#include <platform/timer.h>
+#include <kernel/event.h>
+#include <target.h>
+#include <string.h>
+#include <stdlib.h>
+#include <bits.h>
+#include <debug.h>
+#include <sdhci.h>
+
+
+/*
+ * Function: sdhci int handler
+ * Arg : Event argument
+ * Return : 0
+ * Flow: : 1. Read the power control mask register
+ * 2. Check if bus is ON
+ * 3. Write success to ack regiser
+ * Details : This is power control interrupt handler.
+ * Once we receive the interrupt, we will ack the power control
+ * register that we have successfully completed pmic transactions
+ */
+enum handler_return sdhci_int_handler(void *arg)
+{
+ uint32_t ack;
+ uint32_t status;
+
+ /*
+ * Read the mask register to check if BUS & IO level
+ * interrupts are enabled
+ */
+ status = readl(SDCC_HC_PWRCTL_MASK_REG);
+
+ if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
+ ack = SDCC_HC_BUS_ON_OFF_SUCC;
+ if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
+ ack |= SDCC_HC_IO_SIG_SUCC;
+
+ /* Write success to power control register */
+ writel(ack, SDCC_HC_PWRCTL_CTL_REG);
+
+ event_signal((event_t *)arg, false);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci error status enable
+ * Arg : Host structure
+ * Return : None
+ * Flow: : Enable command error status
+ */
+static void sdhci_error_status_enable(struct sdhci_host *host)
+{
+ /* Enable all interrupt status */
+ REG_WRITE16(host, SDHCI_NRML_INT_STS_EN, SDHCI_NRML_INT_STS_EN_REG);
+ REG_WRITE16(host, SDHCI_ERR_INT_STS_EN, SDHCI_ERR_INT_STS_EN_REG);
+ /* Enable all interrupt signal */
+ REG_WRITE16(host, SDHCI_NRML_INT_SIG_EN, SDHCI_NRML_INT_SIG_EN_REG);
+ REG_WRITE16(host, SDHCI_ERR_INT_SIG_EN, SDHCI_ERR_INT_SIG_EN_REG);
+}
+
+/*
+ * Function: sdhci clock supply
+ * Arg : Host structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow: : 1. Calculate the clock divider
+ * 2. Set the clock divider
+ * 3. Check if clock stable
+ * 4. Enable Clock
+ */
+uint32_t sdhci_clk_supply(struct sdhci_host *host, uint32_t clk)
+{
+ uint32_t div = 0;
+ uint32_t freq = 0;
+ uint16_t clk_val = 0;
+
+ if (clk > host->caps.base_clk_rate) {
+ dprintf(CRITICAL, "Error: Requested clk freq is more than supported\n");
+ return 1;
+ }
+
+ if (clk == host->caps.base_clk_rate)
+ goto clk_ctrl;
+
+ /* As per the sd spec div should be a multiplier of 2 */
+ for (div = 2; div < SDHCI_CLK_MAX_DIV; div += 2) {
+ freq = host->caps.base_clk_rate / div;
+ if (freq <= clk)
+ break;
+ }
+
+ div >>= 1;
+
+clk_ctrl:
+ /* As per the sdhci spec 3.0, bits 6-7 of the clock
+ * control registers will be mapped to bit 8-9, to
+ * support a 10 bit divider value.
+ * This is needed when the divider value overflows
+ * the 8 bit range.
+ */
+ clk_val = ((div & SDHCI_SDCLK_FREQ_MASK) << SDHCI_SDCLK_FREQ_SEL);
+ clk_val |= ((div & SDHC_SDCLK_UP_BIT_MASK) >> SDHCI_SDCLK_FREQ_SEL)
+ << SDHCI_SDCLK_UP_BIT_SEL;
+
+ clk_val |= SDHCI_INT_CLK_EN;
+ REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG);
+
+ /* Check for clock stable */
+ while (!(REG_READ16(host, SDHCI_CLK_CTRL_REG) & SDHCI_CLK_STABLE));
+
+ /* Now clock is stable, enable it */
+ clk_val = REG_READ16(host, SDHCI_CLK_CTRL_REG);
+ clk_val |= SDHCI_CLK_EN;
+ REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG);
+
+ host->cur_clk_rate = freq;
+
+ return 0;
+}
+
+/*
+ * Function: sdhci stop sdcc clock
+ * Arg : Host structure
+ * Return : 0 on Success, 1 on Failure
+ * Flow: : 1. Stop the clock
+ */
+static uint32_t sdhci_stop_sdcc_clk(struct sdhci_host *host)
+{
+ uint32_t reg;
+
+ reg = REG_READ32(host, SDHCI_PRESENT_STATE_REG);
+
+ if (reg & (SDHCI_CMD_ACT | SDHCI_DAT_ACT)) {
+ dprintf(CRITICAL, "Error: SDCC command & data line are active\n");
+ return 1;
+ }
+
+ REG_WRITE16(host, SDHCI_CLK_DIS, SDHCI_CLK_CTRL_REG);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci change frequency
+ * Arg : Host structure & clock value
+ * Return : 0 on Success, 1 on Failure
+ * Flow: : 1. Stop the clock
+ * 2. Star the clock with new frequency
+ */
+static uint32_t sdhci_change_freq_clk(struct sdhci_host *host, uint32_t clk)
+{
+ if (sdhci_stop_sdcc_clk(host)) {
+ dprintf(CRITICAL, "Error: Card is busy, cannot change frequency\n");
+ return 1;
+ }
+
+ if (sdhci_clk_supply(host, clk)) {
+ dprintf(CRITICAL, "Error: cannot change frequency\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: sdhci set bus power
+ * Arg : Host structure
+ * Return : None
+ * Flow: : 1. Set the voltage
+ * 2. Set the sd power control register
+ */
+static void sdhci_set_bus_power_on(struct sdhci_host *host)
+{
+ uint8_t voltage;
+
+ voltage = host->caps.voltage;
+
+ voltage <<= SDHCI_BUS_VOL_SEL;
+ REG_WRITE8(host, voltage, SDHCI_BUS_PWR_EN);
+
+ voltage |= SDHCI_BUS_PWR_EN;
+
+ REG_WRITE8(host, voltage, SDHCI_PWR_CTRL_REG);
+
+}
+
+/*
+ * Function: sdhci set SDR mode
+ * Arg : Host structure
+ * Return : None
+ * Flow: : 1. Disable the clock
+ * 2. Enable sdr mode
+ * 3. Enable the clock
+ * Details : SDR50/SDR104 mode is nothing but HS200
+ * mode SDCC spec refers to it as SDR mode
+ * & emmc spec refers as HS200 mode.
+ */
+void sdhci_set_sdr_mode(struct sdhci_host *host)
+{
+ uint16_t clk;
+ uint16_t ctrl = 0;
+
+ /* Disable the clock */
+ clk = REG_READ16(host, SDHCI_CLK_CTRL_REG);
+ clk &= ~SDHCI_CLK_EN;
+ REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG);
+
+ /* Enable SDR50 mode:
+ * Right now we support only SDR50 mode which runs at
+ * 100 MHZ sdcc clock, we dont need tuning with SDR50
+ * mode
+ */
+ ctrl = REG_READ16(host, SDHCI_HOST_CTRL2_REG);
+
+ /* Enable SDR50/SDR104 mode based on the controller
+ * capabilities.
+ */
+ if (host->caps.sdr50_support)
+ ctrl |= SDHCI_SDR50_MODE_EN;
+
+ REG_WRITE16(host, ctrl, SDHCI_HOST_CTRL2_REG);
+
+ /* Run the clock back */
+ sdhci_clk_supply(host, SDHCI_CLK_100MHZ);
+}
+
+/*
+ * Function: sdhci set ddr mode
+ * Arg : Host structure
+ * Return : None
+ * Flow: : 1. Disable the clock
+ * 2. Enable DDR mode
+ * 3. Enable the clock
+ */
+void sdhci_set_ddr_mode(struct sdhci_host *host)
+{
+ uint16_t clk;
+ uint16_t ctrl = 0;
+
+ /* Disable the clock */
+ clk = REG_READ16(host, SDHCI_CLK_CTRL_REG);
+ clk &= ~SDHCI_CLK_EN;
+ REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG);
+
+ ctrl = REG_READ16(host, SDHCI_HOST_CTRL2_REG);
+ ctrl |= SDHCI_DDR_MODE_EN;
+
+ /* Enalbe DDR mode */
+ REG_WRITE16(host, ctrl, SDHCI_HOST_CTRL2_REG);
+
+ /* Run the clock back */
+ sdhci_clk_supply(host, host->cur_clk_rate);
+}
+
+/*
+ * Function: sdhci set adma mode
+ * Arg : Host structure
+ * Return : None
+ * Flow: : Set adma mode
+ */
+static void sdhci_set_adma_mode(struct sdhci_host *host)
+{
+ /* Select 32 Bit ADMA2 type */
+ REG_WRITE8(host, SDHCI_ADMA_32BIT, SDHCI_HOST_CTRL1_REG);
+}
+
+/*
+ * Function: sdhci set bus width
+ * Arg : Host & width
+ * Return : 0 on Sucess, 1 on Failure
+ * Flow: : Set the bus width for controller
+ */
+uint8_t sdhci_set_bus_width(struct sdhci_host *host, uint16_t width)
+{
+ uint16_t reg = 0;
+
+ reg = REG_READ8(host, SDHCI_HOST_CTRL1_REG);
+
+ switch(width) {
+ case DATA_BUS_WIDTH_8BIT:
+ width = SDHCI_BUS_WITDH_8BIT;
+ break;
+ case DATA_BUS_WIDTH_4BIT:
+ width = SDHCI_BUS_WITDH_4BIT;
+ break;
+ case DATA_BUS_WIDTH_1BIT:
+ width = SDHCI_BUS_WITDH_1BIT;
+ break;
+ default:
+ dprintf(CRITICAL, "Bus width is invalid: %u\n", width);
+ return 1;
+ }
+
+ REG_WRITE8(host, (reg | width), SDHCI_HOST_CTRL1_REG);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci command err status
+ * Arg : Host structure
+ * Return : 0 on Sucess, 1 on Failure
+ * Flow: : Look for error status
+ */
+static uint8_t sdhci_cmd_err_status(struct sdhci_host *host)
+{
+ uint32_t err;
+
+ err = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
+
+ if (err & SDHCI_CMD_TIMEOUT_MASK) {
+ dprintf(CRITICAL, "Error: Command timeout error\n");
+ return 1;
+ } else if (err & SDHCI_CMD_CRC_MASK) {
+ dprintf(CRITICAL, "Error: Command CRC error\n");
+ return 1;
+ } else if (err & SDHCI_CMD_END_BIT_MASK) {
+ dprintf(CRITICAL, "Error: CMD end bit error\n");
+ return 1;
+ } else if (err & SDHCI_CMD_IDX_MASK) {
+ dprintf(CRITICAL, "Error: Command Index error\n");
+ return 1;
+ } else if (err & SDHCI_DAT_TIMEOUT_MASK) {
+ dprintf(CRITICAL, "Error: DATA time out error\n");
+ return 1;
+ } else if (err & SDHCI_DAT_CRC_MASK) {
+ dprintf(CRITICAL, "Error: DATA CRC error\n");
+ return 1;
+ } else if (err & SDHCI_DAT_END_BIT_MASK) {
+ dprintf(CRITICAL, "Error: DATA end bit error\n");
+ return 1;
+ } else if (err & SDHCI_CUR_LIM_MASK) {
+ dprintf(CRITICAL, "Error: Current limit error\n");
+ return 1;
+ } else if (err & SDHCI_AUTO_CMD12_MASK) {
+ dprintf(CRITICAL, "Error: Auto CMD12 error\n");
+ return 1;
+ } else if (err & SDHCI_ADMA_MASK) {
+ dprintf(CRITICAL, "Error: ADMA error\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Function: sdhci command complete
+ * Arg : Host & command structure
+ * Return : 0 on Sucess, 1 on Failure
+ * Flow: : 1. Check for command complete
+ * 2. Check for transfer complete
+ * 3. Get the command response
+ * 4. Check for errors
+ */
+static uint8_t sdhci_cmd_complete(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ uint8_t i;
+ uint16_t retry = 0;
+ uint32_t int_status;
+
+ do {
+ int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
+ int_status &= SDHCI_INT_STS_CMD_COMPLETE;
+
+ if (int_status == SDHCI_INT_STS_CMD_COMPLETE)
+ break;
+
+ retry++;
+ udelay(500);
+ if (retry == SDHCI_MAX_CMD_RETRY) {
+ dprintf(CRITICAL, "Error: Command never completed\n");
+ goto err;
+ }
+ } while(1);
+
+ /* Command is complete, clear the interrupt bit */
+ REG_WRITE16(host, SDHCI_INT_STS_CMD_COMPLETE, SDHCI_NRML_INT_STS_REG);
+
+ /* Copy the command response,
+ * The valid bits for R2 response are 0-119, & but the actual response
+ * is stored in bits 8-128. We need to move 8 bits of MSB of each
+ * response to register 8 bits of LSB of next response register.
+ * As:
+ * MSB 8 bits of RESP0 --> LSB 8 bits of RESP1
+ * MSB 8 bits of RESP1 --> LSB 8 bits of RESP2
+ * MSB 8 bits of RESP2 --> LSB 8 bits of RESP3
+ */
+ if (cmd->resp_type == SDHCI_CMD_RESP_R2) {
+ for (i = 0; i < 4; i++) {
+ cmd->resp[i] = REG_READ32(host, SDHCI_RESP_REG + (i * 4));
+ cmd->resp[i] <<= SDHCI_RESP_LSHIFT;
+
+ if (i != 0)
+ cmd->resp[i] |= (REG_READ32(host, SDHCI_RESP_REG + ((i-1) * 4)) >> SDHCI_RESP_RSHIFT);
+ }
+ } else
+ cmd->resp[0] = REG_READ32(host, SDHCI_RESP_REG);
+
+ retry = 0;
+
+ /*
+ * Clear the transfer complete interrupt
+ */
+ if (cmd->data_present || cmd->cmd_index == SDHCI_SWITCH_CMD) {
+ do {
+ int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
+ int_status &= SDHCI_INT_STS_TRANS_COMPLETE;
+
+ if (int_status & SDHCI_INT_STS_TRANS_COMPLETE)
+ break;
+
+ retry++;
+ udelay(1000);
+ if (retry == SDHCI_MAX_TRANS_RETRY) {
+ dprintf(CRITICAL, "Error: Transfer never completed\n");
+ goto err;
+ }
+ } while(1);
+
+ /* Transfer is complete, clear the interrupt bit */
+ REG_WRITE16(host, SDHCI_INT_STS_TRANS_COMPLETE, SDHCI_NRML_INT_STS_REG);
+ }
+
+err:
+ /* Look for errors */
+ int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG);
+ if (int_status & SDHCI_ERR_INT_STAT_MASK) {
+ if (sdhci_cmd_err_status(host)) {
+ dprintf(CRITICAL, "Error: Command completed with errors\n");
+ return 1;
+ }
+ }
+
+ /* Reset data & command line */
+ if (cmd->data_present)
+ REG_WRITE8(host, (SOFT_RESET_CMD | SOFT_RESET_DATA), SDHCI_RESET_REG);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci prep desc table
+ * Arg : Pointer data & length
+ * Return : Pointer to desc table
+ * Flow: : Prepare the adma table as per the sd spec v 3.0
+ */
+static struct desc_entry *sdhci_prep_desc_table(void *data, uint32_t len)
+{
+ struct desc_entry *sg_list;
+ uint32_t sg_len = 0;
+ uint32_t remain = 0;
+ uint32_t i;
+ uint32_t table_len = 0;
+
+ if (len <= SDHCI_ADMA_DESC_LINE_SZ) {
+ /* Allocate only one descriptor */
+ sg_list = (struct desc_entry *) memalign(4, sizeof(struct desc_entry));
+
+ if (!sg_list) {
+ dprintf(CRITICAL, "Error allocating memory\n");
+ ASSERT(0);
+ }
+
+ sg_list[0].addr = data;
+ sg_list[0].len = len;
+ sg_list[0].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
+ | SDHCI_ADMA_TRANS_END;
+
+ arch_clean_invalidate_cache_range((addr_t)sg_list, sizeof(struct desc_entry));
+ } else {
+ /* Calculate the number of entries in desc table */
+ sg_len = len / SDHCI_ADMA_DESC_LINE_SZ;
+ remain = len - (sg_len * SDHCI_ADMA_DESC_LINE_SZ);
+ /* Allocate sg_len + 1 entries */
+ if (remain)
+ sg_len++;
+
+ table_len = (sg_len * sizeof(struct desc_entry));
+
+ sg_list = (struct desc_entry *) memalign(4, table_len);
+
+ if (!sg_list) {
+ dprintf(CRITICAL, "Error allocating memory\n");
+ ASSERT(0);
+ }
+
+ memset((void *) sg_list, 0, table_len);
+
+ /*
+ * Prepare sglist in the format:
+ * ___________________________________________________
+ * |Transfer Len | Transfer ATTR | Data Address |
+ * | (16 bit) | (16 bit) | (32 bit) |
+ * |_____________|_______________|_____________________|
+ */
+ for (i = 0; i < (sg_len - 1); i++) {
+ sg_list[i].addr = data;
+ sg_list[i].len = SDHCI_ADMA_DESC_LINE_SZ;
+ sg_list[i].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA;
+ data += SDHCI_ADMA_DESC_LINE_SZ;
+ len -= SDHCI_ADMA_DESC_LINE_SZ;
+ }
+
+ /* Fill the last entry of the table with Valid & End
+ * attributes
+ */
+ sg_list[sg_len - 1].addr = data;
+ sg_list[sg_len - 1].len = len;
+ sg_list[sg_len - 1].tran_att = SDHCI_ADMA_TRANS_VALID | SDHCI_ADMA_TRANS_DATA
+ | SDHCI_ADMA_TRANS_END;
+ }
+
+ arch_clean_invalidate_cache_range((addr_t)sg_list, table_len);
+
+ return sg_list;
+}
+
+/*
+ * Function: sdhci adma transfer
+ * Arg : Host structure & command stucture
+ * Return : Pointer to desc table
+ * Flow : 1. Prepare data transfer properties
+ * 2. Write adma register
+ * 3. Write transfer mode register
+ */
+static struct desc_entry *sdhci_adma_transfer(struct sdhci_host *host,
+ struct mmc_command *cmd)
+{
+ uint32_t num_blks = 0;
+ uint32_t sz;
+ uint16_t trans_mode = 0;
+ void *data;
+ struct desc_entry *adma_addr;
+
+
+ num_blks = cmd->data.num_blocks;
+ data = cmd->data.data_ptr;
+
+ sz = num_blks * SDHCI_MMC_BLK_SZ;
+
+ /* Prepare adma descriptor table */
+ adma_addr = sdhci_prep_desc_table(data, sz);
+
+ /* Write the block size */
+ REG_WRITE16(host, SDHCI_MMC_BLK_SZ, SDHCI_BLKSZ_REG);
+
+ /* Enalbe auto cmd 23 for multi block transfer */
+ if (num_blks > 1) {
+ trans_mode |= SDHCI_TRANS_MULTI | SDHCI_AUTO_CMD23_EN | SDHCI_BLK_CNT_EN;
+ REG_WRITE32(host, num_blks, SDHCI_ARG2_REG);
+ }
+
+ /*
+ * Set block count in block count register
+ */
+
+ REG_WRITE16(host, num_blks, SDHCI_BLK_CNT_REG);
+
+ if (cmd->trans_mode == SDHCI_MMC_READ)
+ trans_mode |= SDHCI_READ_MODE;
+
+ trans_mode |= SDHCI_DMA_EN;
+
+ /* Write adma address to adma register */
+ REG_WRITE32(host, (uint32_t) adma_addr, SDHCI_ADM_ADDR_REG);
+
+ /* Set transfer mode */
+ REG_WRITE16(host, trans_mode, SDHCI_TRANS_MODE_REG);
+
+ return adma_addr;
+}
+
+/*
+ * Function: sdhci send command
+ * Arg : Host structure & command stucture
+ * Return : 0 on Success, 1 on Failure
+ * Flow: : 1. Prepare the command register
+ * 2. If data is present, prepare adma table
+ * 3. Run the command
+ * 4. Check for command results & take action
+ */
+uint32_t sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+{
+ uint8_t retry = 0;
+ uint32_t resp_type = 0;
+ uint16_t present_state;
+ uint32_t flags;
+ struct desc_entry *sg_list = NULL;
+
+ if (cmd->data_present)
+ ASSERT(cmd->data.data_ptr);
+
+ /*
+ * Assert if the data buffer is not aligned to cache
+ * line size for read operations.
+ * For write operations this function assumes that
+ * the cache is already flushed by the caller. As
+ * the data buffer we receive for write operation
+ * may not be aligned to cache boundary due to
+ * certain image formats like sparse image.
+ */
+ if (cmd->trans_mode == SDHCI_READ_MODE)
+ ASSERT(IS_CACHE_LINE_ALIGNED(cmd->data.data_ptr));
+
+ do {
+ present_state = REG_READ32(host, SDHCI_PRESENT_STATE_REG);
+ /* check if CMD & DAT lines are free */
+ present_state &= SDHCI_STATE_CMD_DAT_MASK;
+
+ if (!present_state)
+ break;
+ udelay(1000);
+ retry++;
+ if (retry == 10) {
+ dprintf(CRITICAL, "Error: CMD or DAT lines were never freed\n");
+ return 1;
+ }
+ } while(1);
+
+ switch(cmd->resp_type) {
+ case SDHCI_CMD_RESP_R1:
+ case SDHCI_CMD_RESP_R3:
+ case SDHCI_CMD_RESP_R6:
+ case SDHCI_CMD_RESP_R7:
+ /* Response of length 48 have 32 bits
+ * of response data stored in RESP0[0:31]
+ */
+ resp_type = SDHCI_CMD_RESP_48;
+ break;
+
+ case SDHCI_CMD_RESP_R2:
+ /* Response of length 136 have 120 bits
+ * of response data stored in RESP0[0:119]
+ */
+ resp_type = SDHCI_CMD_RESP_136;
+ break;
+
+ case SDHCI_CMD_RESP_R1B:
+ /* Response of length 48 have 32 bits
+ * of response data stored in RESP0[0:31]
+ * & set CARD_BUSY status if card is busy
+ */
+ resp_type = SDHCI_CMD_RESP_48_BUSY;
+ break;
+
+ case SDHCI_CMD_RESP_NONE:
+ resp_type = SDHCI_CMD_RESP_NONE;
+ break;
+
+ default:
+ dprintf(CRITICAL, "Invalid response type for the command\n");
+ return 1;
+ };
+
+ flags = (resp_type << SDHCI_CMD_RESP_TYPE_SEL_BIT);
+ flags |= (cmd->data_present << SDHCI_CMD_DATA_PRESENT_BIT);
+ flags |= (cmd->cmd_type << SDHCI_CMD_CMD_TYPE_BIT);
+
+ /* Set the timeout value */
+ REG_WRITE8(host, SDHCI_CMD_TIMEOUT, SDHCI_TIMEOUT_REG);
+
+ /* Check if data needs to be processed */
+ if (cmd->data_present)
+ sg_list = sdhci_adma_transfer(host, cmd);
+
+ /* Write the argument 1 */
+ REG_WRITE32(host, cmd->argument, SDHCI_ARGUMENT_REG);
+
+ /* Write the command register */
+ REG_WRITE16(host, SDHCI_PREP_CMD(cmd->cmd_index, flags), SDHCI_CMD_REG);
+
+ /* Command complete sequence */
+ if (sdhci_cmd_complete(host, cmd))
+ return 1;
+
+ /* Invalidate the cache only for read operations */
+ if (cmd->trans_mode == SDHCI_MMC_READ)
+ arch_invalidate_cache_range((addr_t)cmd->data.data_ptr, (cmd->data.num_blocks * SDHCI_MMC_BLK_SZ));
+
+ /* Free the scatter/gather list */
+ if (sg_list)
+ free(sg_list);
+
+ return 0;
+}
+
+/*
+ * Function: sdhci reset
+ * Arg : Host structure
+ * Return : None
+ * Flow: : Reset the host controller
+ */
+static void sdhci_reset(struct sdhci_host *host)
+{
+ uint32_t reg;
+
+ REG_WRITE8(host, SDHCI_SOFT_RESET, SDHCI_RESET_REG);
+
+ /* Wait for the reset to complete */
+ do {
+ reg = REG_READ8(host, SDHCI_RESET_REG);
+ reg &= SDHCI_SOFT_RESET_MASK;
+
+ if (!reg)
+ break;
+ } while(1);
+}
+
+/*
+ * Function: sdhci mode enable
+ * Arg : Flag (0/1)
+ * Return : None
+ * Flow: : Enable/Disable Sdhci mode
+ */
+void sdhci_mode_enable(uint8_t enable)
+{
+ if (enable)
+ writel(SDHCI_HC_MODE_EN, SDCC_MCI_HC_MODE);
+ else
+ writel(SDHCI_HC_MODE_DIS, SDCC_MCI_HC_MODE);
+}
+
+/*
+ * Function: sdhci init
+ * Arg : Host structure
+ * Return : None
+ * Flow: : 1. Reset the controller
+ * 2. Read the capabilities register & populate the host
+ * controller capabilities for use by other functions
+ * 3. Enable the power control
+ * 4. Set initial bus width
+ * 5. Set Adma mode
+ * 6. Enable the error status
+ */
+void sdhci_init(struct sdhci_host *host)
+{
+ uint32_t caps[2];
+ event_t sdhc_event;
+
+ event_init(&sdhc_event, false, EVENT_FLAG_AUTOUNSIGNAL);
+
+ /*
+ * Reset the controller
+ */
+ sdhci_reset(host);
+
+ /* Read the capabilities register & store the info */
+ caps[0] = REG_READ32(host, SDHCI_CAPS_REG1);
+ caps[1] = REG_READ32(host, SDHCI_CAPS_REG2);
+
+ host->caps.base_clk_rate = (caps[0] & SDHCI_CLK_RATE_MASK) >> SDHCI_CLK_RATE_BIT;
+ host->caps.base_clk_rate *= 1000000;
+
+ /* Get the max block length for mmc */
+ host->caps.max_blk_len = (caps[0] & SDHCI_BLK_LEN_MASK) >> SDHCI_BLK_LEN_BIT;
+
+ /* 8 bit Bus width */
+ if (caps[0] & SDHCI_8BIT_WIDTH_MASK)
+ host->caps.bus_width_8bit = 1;
+
+ /* Adma support */
+ if (caps[0] & SDHCI_BLK_ADMA_MASK)
+ host->caps.adma_support = 1;
+
+ /* Supported voltage */
+ if (caps[0] & SDHCI_3_3_VOL_MASK)
+ host->caps.voltage = SDHCI_VOL_3_3;
+ else if (caps[0] & SDHCI_3_0_VOL_MASK)
+ host->caps.voltage = SDHCI_VOL_3_0;
+ else if (caps[0] & SDHCI_1_8_VOL_MASK)
+ host->caps.voltage = SDHCI_VOL_1_8;
+
+ /* DDR mode support */
+ host->caps.ddr_support = (caps[1] & SDHCI_DDR_MODE_MASK) ? 1 : 0;
+
+ /* SDR50 mode support */
+ host->caps.sdr50_support = (caps[1] & SDHCI_SDR50_MODE_MASK) ? 1 : 0;
+
+ /*
+ * Register the interrupt handler for pwr irq
+ */
+ register_int_handler(SDCC_PWRCTRL_IRQ, sdhci_int_handler, &sdhc_event);
+ unmask_interrupt(SDCC_PWRCTRL_IRQ);
+
+ /* Enable pwr control interrupt */
+ writel(SDCC_HC_PWR_CTRL_INT, SDCC_HC_PWRCTL_MASK_REG);
+
+ /* Set bus power on */
+ sdhci_set_bus_power_on(host);
+
+ /* Wait for power interrupt to be handled */
+ event_wait(&sdhc_event);
+
+ /* Set bus width */
+ sdhci_set_bus_width(host, SDHCI_BUS_WITDH_1BIT);
+
+ /* Set Adma mode */
+ sdhci_set_adma_mode(host);
+
+ /*
+ * Enable error status
+ */
+ sdhci_error_status_enable(host);
+}
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index e0cbc5b..4749959 100755
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -297,6 +297,8 @@
MSM8627AA = 182,
MSM8227AA = 183,
APQ8074 = 184,
+ MSM8274 = 185,
+ MSM8674 = 186,
};
enum platform {
diff --git a/project/msm8226.mk b/project/msm8226.mk
index a9d45b2..262abc8 100644
--- a/project/msm8226.mk
+++ b/project/msm8226.mk
@@ -7,6 +7,7 @@
MODULES += app/aboot
DEBUG := 1
+ENABLE_SDHCI_SUPPORT := 1
#DEFINES += WITH_DEBUG_DCC=1
DEFINES += WITH_DEBUG_UART=1
@@ -14,3 +15,7 @@
DEFINES += DEVICE_TREE=1
#DEFINES += MMC_BOOT_BAM=1
DEFINES += CRYPTO_BAM=1
+
+ifeq ($(ENABLE_SDHCI_SUPPORT),1)
+DEFINES += MMC_SDHCI_SUPPORT=1
+endif
diff --git a/project/msm8974.mk b/project/msm8974.mk
index 6ffa254..5bb9a4b 100644
--- a/project/msm8974.mk
+++ b/project/msm8974.mk
@@ -8,6 +8,7 @@
DEBUG := 1
EMMC_BOOT := 1
+ENABLE_SDHCI_SUPPORT := 0
#DEFINES += WITH_DEBUG_DCC=1
DEFINES += WITH_DEBUG_UART=1
@@ -27,3 +28,7 @@
ifeq ($(EMMC_BOOT),1)
DEFINES += _EMMC_BOOT=1
endif
+
+ifeq ($(ENABLE_SDHCI_SUPPORT),1)
+DEFINES += MMC_SDHCI_SUPPORT=1
+endif
diff --git a/target/init.c b/target/init.c
index 78a7bad..937f136 100644
--- a/target/init.c
+++ b/target/init.c
@@ -24,7 +24,6 @@
#include <debug.h>
#include <target.h>
#include <compiler.h>
-#include <mmc.h>
#define EXPAND(NAME) #NAME
#define TARGET(NAME) EXPAND(NAME)
@@ -69,6 +68,11 @@
{
}
+__WEAK int set_download_mode(void)
+{
+ return -1;
+}
+
__WEAK unsigned target_pause_for_battery_charge(void)
{
return 0;
@@ -118,14 +122,3 @@
__WEAK void target_usb_stop(void)
{
}
-
-/*
- * Default target specific function to set the capabilities for the host
- */
-__WEAK void target_mmc_caps(struct mmc_host *host)
-{
- host->caps.ddr_mode = 0;
- host->caps.hs200_mode = 0;
- host->caps.bus_width = MMC_BOOT_BUS_WIDTH_4_BIT;
- host->caps.hs_clk_rate = MMC_CLK_50MHZ;
-}
diff --git a/target/msm7627a/init.c b/target/msm7627a/init.c
index 2bb46c2..502cb54 100644
--- a/target/msm7627a/init.c
+++ b/target/msm7627a/init.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2009, Google Inc.
* All rights reserved.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -722,3 +722,12 @@
};
return ret;
}
+
+/* Function to set the capabilities for the host */
+void target_mmc_caps(struct mmc_host *host)
+{
+ host->caps.ddr_mode = 0;
+ host->caps.hs200_mode = 0;
+ host->caps.bus_width = MMC_BOOT_BUS_WIDTH_4_BIT;
+ host->caps.hs_clk_rate = MMC_CLK_50MHZ;
+}
diff --git a/target/msm8226/init.c b/target/msm8226/init.c
index ff994d1..571bf20 100644
--- a/target/msm8226/init.c
+++ b/target/msm8226/init.c
@@ -31,8 +31,9 @@
#include <reg.h>
#include <target.h>
#include <platform.h>
+#include <dload_util.h>
#include <uart_dm.h>
-#include <mmc.h>
+#include <mmc_sdhci.h>
#include <platform/gpio.h>
#include <spmi.h>
#include <board.h>
@@ -44,6 +45,7 @@
#include <hsusb.h>
extern bool target_use_signed_kernel(void);
+static void set_sdc_power_ctrl(void);
#define PMIC_ARB_CHANNEL_NUM 0
#define PMIC_ARB_OWNER_ID 0
@@ -57,8 +59,10 @@
#define TLMM_VOL_UP_BTN_GPIO 106
-static uint32_t mmc_sdc_base[] =
- { MSM_SDC1_BASE, MSM_SDC2_BASE, MSM_SDC3_BASE };
+static uint32_t mmc_sdhci_base[] =
+ { MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE, MSM_SDC3_SDHCI_BASE };
+
+struct mmc_device *dev;
void target_early_init(void)
{
@@ -124,31 +128,53 @@
crypto_init_params(&ce_params);
}
+void target_sdc_init()
+{
+ struct mmc_config_data config;
+
+ /*
+ * Set drive strength & pull ctrl for emmc
+ */
+ set_sdc_power_ctrl();
+
+ /* Enable sdhci mode */
+ sdhci_mode_enable(1);
+
+ config.bus_width = DATA_BUS_WIDTH_8BIT;
+ config.max_clk_rate = MMC_CLK_200MHZ;
+
+ /* Trying Slot 1*/
+ config.slot = 1;
+ config.base = mmc_sdhci_base[config.slot - 1];
+ if (!(dev = mmc_init(&config)))
+ {
+ /* Trying Slot 2 next */
+ config.slot = 2;
+ config.base = mmc_sdhci_base[config.slot - 1];
+ if (!(dev = mmc_init(&config))) {
+ dprintf(CRITICAL, "mmc init failed!");
+ ASSERT(0);
+ }
+ }
+
+ /*
+ * MMC initialization is complete, read the partition table info
+ */
+ if (partition_read_table()) {
+ dprintf(CRITICAL, "Error reading the partition table info\n");
+ ASSERT(0);
+ }
+}
+
void target_init(void)
{
- uint32_t base_addr;
- uint8_t slot;
-
dprintf(INFO, "target_init()\n");
spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
target_keystatus();
- /* Trying Slot 1*/
- slot = 1;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr))
- {
-
- /* Trying Slot 2 next */
- slot = 2;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr)) {
- dprintf(CRITICAL, "mmc init failed!");
- ASSERT(0);
- }
- }
+ target_sdc_init();
if (target_use_signed_kernel())
target_crypto_init_params();
@@ -290,3 +316,43 @@
{
return board_baseband();
}
+
+int emmc_recovery_init(void)
+{
+ return _emmc_recovery_init();
+}
+
+int set_download_mode(void)
+{
+ dload_util_write_cookie(FORCE_DLOAD_MODE_ADDR);
+
+ return 0;
+}
+
+static void set_sdc_power_ctrl()
+{
+ /* Drive strength configs for sdc pins */
+ struct tlmm_cfgs sdc1_hdrv_cfg[] =
+ {
+ { SDC1_CLK_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+ { SDC1_CMD_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+ { SDC1_DATA_HDRV_CTL_OFF, TLMM_CUR_VAL_10MA, TLMM_HDRV_MASK },
+ };
+
+ /* Pull configs for sdc pins */
+ struct tlmm_cfgs sdc1_pull_cfg[] =
+ {
+ { SDC1_CLK_PULL_CTL_OFF, TLMM_NO_PULL, TLMM_PULL_MASK },
+ { SDC1_CMD_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK },
+ { SDC1_DATA_PULL_CTL_OFF, TLMM_PULL_UP, TLMM_PULL_MASK },
+ };
+
+ /* Set the drive strength & pull control values */
+ tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
+ tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
+}
+
+struct mmc_device *target_mmc_device()
+{
+ return dev;
+}
diff --git a/target/msm8610/init.c b/target/msm8610/init.c
index 4a5bda1..6537a4d 100644
--- a/target/msm8610/init.c
+++ b/target/msm8610/init.c
@@ -41,6 +41,7 @@
#include <dev/keys.h>
#include <pm8x41.h>
#include <hsusb.h>
+#include <kernel/thread.h>
#define PMIC_ARB_CHANNEL_NUM 0
#define PMIC_ARB_OWNER_ID 0
@@ -64,6 +65,8 @@
gpio_tlmm_config(TLMM_VOL_UP_BTN_GPIO, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_2MA, GPIO_ENABLE);
+ /* Wait for the configuration to complete.*/
+ thread_sleep(1);
/* Get status of GPIO */
status = gpio_status(TLMM_VOL_UP_BTN_GPIO);
@@ -254,3 +257,14 @@
{
return 0;
}
+
+/*
+ * Function to set the capabilities for the host
+ */
+void target_mmc_caps(struct mmc_host *host)
+{
+ host->caps.ddr_mode = 0;
+ host->caps.hs200_mode = 0;
+ host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
+ host->caps.hs_clk_rate = MMC_CLK_50MHZ;
+}
diff --git a/target/msm8974/init.c b/target/msm8974/init.c
index 0ec0b1f..fb9da87 100644
--- a/target/msm8974/init.c
+++ b/target/msm8974/init.c
@@ -32,6 +32,7 @@
#include <reg.h>
#include <target.h>
#include <platform.h>
+#include <dload_util.h>
#include <uart_dm.h>
#include <mmc.h>
#include <spmi.h>
@@ -46,6 +47,7 @@
#include <partition_parser.h>
#include <scm.h>
#include <platform/clock.h>
+#include <platform/gpio.h>
#include <stdlib.h>
extern bool target_use_signed_kernel(void);
@@ -54,6 +56,10 @@
static unsigned int target_id;
static uint32_t pmic_ver;
+#if MMC_SDHCI_SUPPORT
+struct mmc_device *dev;
+#endif
+
#define PMIC_ARB_CHANNEL_NUM 0
#define PMIC_ARB_OWNER_ID 0
@@ -71,6 +77,11 @@
#define SSD_PARTITION_SIZE 8192
#endif
+#if MMC_SDHCI_SUPPORT
+static uint32_t mmc_sdhci_base[] =
+ { MSM_SDC1_SDHCI_BASE, MSM_SDC2_SDHCI_BASE, MSM_SDC3_SDHCI_BASE, MSM_SDC4_SDHCI_BASE };
+#endif
+
static uint32_t mmc_sdc_base[] =
{ MSM_SDC1_BASE, MSM_SDC2_BASE, MSM_SDC3_BASE, MSM_SDC4_BASE };
@@ -157,11 +168,110 @@
return CRYPTO_ENGINE_TYPE_HW;
}
-void target_init(void)
+#if MMC_SDHCI_SUPPORT
+static target_mmc_sdhci_init()
+{
+ struct mmc_config_data config;
+ uint32_t soc_ver = 0;
+
+ /* Enable sdhci mode */
+ sdhci_mode_enable(1);
+
+ soc_ver = board_soc_version();
+
+ /*
+ * 8974 v1 fluid devices, have a hardware bug
+ * which limits the bus width to 4 bit.
+ */
+ switch(board_hardware_id())
+ {
+ case HW_PLATFORM_FLUID:
+ if (soc_ver >= BOARD_SOC_VERSION2)
+ config.bus_width = DATA_BUS_WIDTH_8BIT;
+ else
+ config.bus_width = DATA_BUS_WIDTH_4BIT;
+ break;
+ default:
+ config.bus_width = DATA_BUS_WIDTH_8BIT;
+ };
+
+ config.max_clk_rate = MMC_CLK_200MHZ;
+
+ /* Trying Slot 1*/
+ config.slot = 1;
+ config.base = mmc_sdhci_base[config.slot - 1];
+
+ if (!(dev = mmc_init(&config))) {
+ /* Trying Slot 2 next */
+ config.slot = 2;
+ config.base = mmc_sdhci_base[config.slot - 1];
+ if (!(dev = mmc_init(&config))) {
+ dprintf(CRITICAL, "mmc init failed!");
+ ASSERT(0);
+ }
+ }
+}
+
+struct mmc_device *target_mmc_device()
+{
+ return dev;
+}
+#else
+static target_mmc_mci_init()
{
uint32_t base_addr;
uint8_t slot;
+ /* Trying Slot 1 */
+ slot = 1;
+ base_addr = mmc_sdc_base[slot - 1];
+
+ if (mmc_boot_main(slot, base_addr))
+ {
+ /* Trying Slot 2 next */
+ slot = 2;
+ base_addr = mmc_sdc_base[slot - 1];
+ if (mmc_boot_main(slot, base_addr)) {
+ dprintf(CRITICAL, "mmc init failed!");
+ ASSERT(0);
+ }
+ }
+}
+
+/*
+ * Function to set the capabilities for the host
+ */
+void target_mmc_caps(struct mmc_host *host)
+{
+ uint32_t soc_ver = 0;
+
+ soc_ver = board_soc_version();
+
+ /*
+ * 8974 v1 fluid devices, have a hardware bug
+ * which limits the bus width to 4 bit.
+ */
+ switch(board_hardware_id())
+ {
+ case HW_PLATFORM_FLUID:
+ if (soc_ver >= BOARD_SOC_VERSION2)
+ host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
+ else
+ host->caps.bus_width = MMC_BOOT_BUS_WIDTH_4_BIT;
+ break;
+ default:
+ host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
+ };
+
+ host->caps.ddr_mode = 1;
+ host->caps.hs200_mode = 1;
+ host->caps.hs_clk_rate = MMC_CLK_96MHZ;
+}
+#endif
+
+
+void target_init(void)
+{
dprintf(INFO, "target_init()\n");
spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
@@ -186,19 +296,18 @@
*/
set_sdc_power_ctrl();
- /* Trying Slot 1*/
- slot = 1;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr))
- {
+#if MMC_SDHCI_SUPPORT
+ target_mmc_sdhci_init();
+#else
+ target_mmc_mci_init();
+#endif
- /* Trying Slot 2 next */
- slot = 2;
- base_addr = mmc_sdc_base[slot - 1];
- if (mmc_boot_main(slot, base_addr)) {
- dprintf(CRITICAL, "mmc init failed!");
- ASSERT(0);
- }
+ /*
+ * MMC initialization is complete, read the partition table info
+ */
+ if (partition_read_table()) {
+ dprintf(CRITICAL, "Error reading the partition table info\n");
+ ASSERT(0);
}
}
@@ -279,6 +388,9 @@
switch(platform_subtype) {
case HW_PLATFORM_SUBTYPE_UNKNOWN:
break;
+ case HW_PLATFORM_SUBTYPE_MDM:
+ board->baseband = BASEBAND_MDM;
+ return;
default:
dprintf(CRITICAL, "Platform Subtype : %u is not supported\n",platform_subtype);
ASSERT(0);
@@ -286,6 +398,8 @@
switch(platform) {
case MSM8974:
+ case MSM8274:
+ case MSM8674:
board->baseband = BASEBAND_MSM;
break;
case APQ8074:
@@ -368,6 +482,13 @@
dprintf(CRITICAL, "Rebooting failed\n");
}
+int set_download_mode(void)
+{
+ dload_util_write_cookie(FORCE_DLOAD_MODE_ADDR_V2);
+
+ return 0;
+}
+
/* Do target specific usb initialization */
void target_usb_init(void)
{
@@ -451,37 +572,6 @@
mdelay(5000);
dprintf(CRITICAL, "Shutdown failed\n");
-
-}
-
-/*
- * Function to set the capabilities for the host
- */
-void target_mmc_caps(struct mmc_host *host)
-{
- uint32_t soc_ver = 0;
-
- soc_ver = board_soc_version();
-
- /*
- * 8974 v1 fluid devices, have a hardware bug
- * which limits the bus width to 4 bit.
- */
- switch(board_hardware_id())
- {
- case HW_PLATFORM_FLUID:
- if (soc_ver >= BOARD_SOC_VERSION2)
- host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
- else
- host->caps.bus_width = MMC_BOOT_BUS_WIDTH_4_BIT;
- break;
- default:
- host->caps.bus_width = MMC_BOOT_BUS_WIDTH_8_BIT;
- };
-
- host->caps.ddr_mode = 1;
- host->caps.hs200_mode = 1;
- host->caps.hs_clk_rate = MMC_CLK_96MHZ;
}
static void set_sdc_power_ctrl()
@@ -506,3 +596,8 @@
tlmm_set_hdrive_ctrl(sdc1_hdrv_cfg, ARRAY_SIZE(sdc1_hdrv_cfg));
tlmm_set_pull_ctrl(sdc1_pull_cfg, ARRAY_SIZE(sdc1_pull_cfg));
}
+
+int emmc_recovery_init(void)
+{
+ return _emmc_recovery_init();
+}