diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /arch/arm/mach-exynos/board-c1lgt-modems.c | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip |
samsung update 1
Diffstat (limited to 'arch/arm/mach-exynos/board-c1lgt-modems.c')
-rw-r--r-- | arch/arm/mach-exynos/board-c1lgt-modems.c | 1937 |
1 files changed, 1937 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/board-c1lgt-modems.c b/arch/arm/mach-exynos/board-c1lgt-modems.c new file mode 100644 index 00000000000..aa218dbfc6a --- /dev/null +++ b/arch/arm/mach-exynos/board-c1lgt-modems.c @@ -0,0 +1,1937 @@ +/* linux/arch/arm/mach-xxxx/board-c1lgt-modems.c + * Copyright (C) 2010 Samsung Electronics. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/clk.h> + +/* inlcude platform specific file */ +#include <linux/platform_data/modem.h> +#include <mach/sec_modem.h> +#include <mach/gpio.h> +#include <mach/gpio-exynos4.h> +#include <plat/gpio-cfg.h> +#include <mach/regs-mem.h> +#include <plat/regs-srom.h> + +#ifdef CONFIG_USBHUB_USB3503 +#include <linux/i2c.h> +#include <linux/i2c-gpio.h> +#include <linux/platform_data/usb3503.h> +#include <mach/cpufreq.h> +#include <plat/usb-phy.h> +#endif +#include <plat/devs.h> +#include <plat/ehci.h> + +#define SROM_CS0_BASE 0x04000000 +#define SROM_WIDTH 0x01000000 +#define SROM_NUM_ADDR_BITS 14 + +/* For "bus width and wait control (BW)" register */ +enum sromc_attr { + SROMC_DATA_16 = 0x1, /* 16-bit data bus */ + SROMC_BYTE_ADDR = 0x2, /* Byte base address */ + SROMC_WAIT_EN = 0x4, /* Wait enabled */ + SROMC_BYTE_EN = 0x8, /* Byte access enabled */ + SROMC_MASK = 0xF +}; + +/* DPRAM configuration */ +struct sromc_cfg { + enum sromc_attr attr; + unsigned size; + unsigned csn; /* CSn # */ + unsigned addr; /* Start address (physical) */ + unsigned end; /* End address (physical) */ +}; + +/* DPRAM access timing configuration */ +struct sromc_access_cfg { + u32 tacs; /* Address set-up before CSn */ + u32 tcos; /* Chip selection set-up before OEn */ + u32 tacc; /* Access cycle */ + u32 tcoh; /* Chip selection hold on OEn */ + u32 tcah; /* Address holding time after CSn */ + u32 tacp; /* Page mode access cycle at Page mode */ + u32 pmc; /* Page Mode config */ +}; + +/* For CMC221 IDPRAM (Internal DPRAM) */ +#define CMC_IDPRAM_SIZE 0x4000 /* 16 KB */ + +/* FOR CMC221 SFR for IDPRAM */ +#define CMC_INT2CP_REG 0x10 /* Interrupt to CP */ +#define CMC_INT2AP_REG 0x50 +#define CMC_CLR_INT_REG 0x28 /* Clear Interrupt to AP */ +#define CMC_RESET_REG 0x3C +#define CMC_PUT_REG 0x40 /* AP->CP reg for hostbooting */ +#define CMC_GET_REG 0x50 /* CP->AP reg for hostbooting */ + +/* For CBP7.2 EDPRAM (External DPRAM) */ +#define CBP_EDPRAM_SIZE 0x4000 /* 16 KB */ + +#define INT_MASK_REQ_ACK_F 0x0020 +#define INT_MASK_REQ_ACK_R 0x0010 +#define INT_MASK_RES_ACK_F 0x0008 +#define INT_MASK_RES_ACK_R 0x0004 +#define INT_MASK_SEND_F 0x0002 +#define INT_MASK_SEND_R 0x0001 + +#define INT_MASK_REQ_ACK_RFS 0x0400 /* Request RES_ACK_RFS */ +#define INT_MASK_RES_ACK_RFS 0x0200 /* Response of REQ_ACK_RFS */ +#define INT_MASK_SEND_RFS 0x0100 /* Indicate sending RFS data */ + + +/* Function prototypes */ +static void config_dpram_port_gpio(void); +static void init_sromc(void); +static void setup_sromc(unsigned csn, struct sromc_cfg *cfg, + struct sromc_access_cfg *acc_cfg); +static void setup_dpram_speed(unsigned csn, struct sromc_access_cfg *acc_cfg); +static int __init init_modem(void); + +#ifdef CONFIG_USBHUB_USB3503 +static int host_port_enable(int port, int enable); +#else +static int host_port_enable(int port, int enable) +{ + return s5p_ehci_port_control(&s5p_device_ehci, port, enable); +} +#endif + +#ifdef CONFIG_LTE_MODEM_CMC221 +static struct sromc_cfg cmc_idpram_cfg = { + .attr = SROMC_DATA_16, + .size = CMC_IDPRAM_SIZE, +}; + +static struct sromc_access_cfg cmc_idpram_access_cfg[] = { + [DPRAM_SPEED_LOW] = { + /* for 33 MHz clock, 64 cycles */ + .tacs = 0x08 << 28, + .tcos = 0x08 << 24, + .tacc = 0x1F << 16, + .tcoh = 0x08 << 12, + .tcah = 0x08 << 8, + .tacp = 0x00 << 4, + .pmc = 0x00 << 0, + }, + [DPRAM_SPEED_MID] = { + /* for 66 MHz clock, 32 cycles */ + .tacs = 0x01 << 28, + .tcos = 0x01 << 24, + .tacc = 0x1B << 16, + .tcoh = 0x01 << 12, + .tcah = 0x01 << 8, + .tacp = 0x00 << 4, + .pmc = 0x00 << 0, + }, + [DPRAM_SPEED_HIGH] = { + /* for 133 MHz clock, 16 cycles */ + .tacs = 0x01 << 28, + .tcos = 0x01 << 24, + .tacc = 0x0B << 16, + .tcoh = 0x01 << 12, + .tcah = 0x01 << 8, + .tacp = 0x00 << 4, + .pmc = 0x00 << 0, + }, +}; + +/* + magic_code + + access_enable + + fmt_tx_head + fmt_tx_tail + fmt_tx_buff + + raw_tx_head + raw_tx_tail + raw_tx_buff + + fmt_rx_head + fmt_rx_tail + fmt_rx_buff + + raw_rx_head + raw_rx_tail + raw_rx_buff + + mbx_cp2ap + + mbx_ap2cp + = 2 + + 2 + + 2 + 2 + 1336 + + 2 + 2 + 4564 + + 2 + 2 + 1336 + + 2 + 2 + 9124 + + 2 + + 2 + = 16384 +*/ + +#define DP_FMT_TX_BUFF_SZ 1336 +#define DP_RAW_TX_BUFF_SZ 4564 +#define DP_FMT_RX_BUFF_SZ 1336 +#define DP_RAW_RX_BUFF_SZ 9124 + +#define MAX_CMC_IDPRAM_IPC_DEV (IPC_RAW + 1) /* FMT, RAW */ + +struct dpram_ipc_cfg { + u16 magic; + u16 access; + + u16 fmt_tx_head; + u16 fmt_tx_tail; + u8 fmt_tx_buff[DP_FMT_TX_BUFF_SZ]; + + u16 raw_tx_head; + u16 raw_tx_tail; + u8 raw_tx_buff[DP_RAW_TX_BUFF_SZ]; + + u16 fmt_rx_head; + u16 fmt_rx_tail; + u8 fmt_rx_buff[DP_FMT_RX_BUFF_SZ]; + + u16 raw_rx_head; + u16 raw_rx_tail; + u8 raw_rx_buff[DP_RAW_RX_BUFF_SZ]; + + u16 mbx_cp2ap; + u16 mbx_ap2cp; +}; + +struct cmc221_idpram_sfr { + u16 __iomem *int2cp; + u16 __iomem *int2ap; + u16 __iomem *clr_int2ap; + u16 __iomem *reset; + u16 __iomem *msg2cp; + u16 __iomem *msg2ap; +}; + +static struct dpram_ipc_map cmc_ipc_map; +static u8 *cmc_sfr_base; +static struct cmc221_idpram_sfr cmc_sfr; + +/* Function prototypes */ +static void cmc_idpram_reset(void); +static void cmc_idpram_setup_speed(enum dpram_speed); +static int cmc_idpram_wakeup(void); +static void cmc_idpram_sleep(void); +static void cmc_idpram_clr_intr(void); +static u16 cmc_idpram_recv_intr(void); +static void cmc_idpram_send_intr(u16 irq_mask); +static u16 cmc_idpram_recv_msg(void); +static void cmc_idpram_send_msg(u16 msg); + +static u16 cmc_idpram_get_magic(void); +static void cmc_idpram_set_magic(u16 value); +static u16 cmc_idpram_get_access(void); +static void cmc_idpram_set_access(u16 value); + +static u32 cmc_idpram_get_tx_head(int dev_id); +static u32 cmc_idpram_get_tx_tail(int dev_id); +static void cmc_idpram_set_tx_head(int dev_id, u32 head); +static void cmc_idpram_set_tx_tail(int dev_id, u32 tail); +static u8 __iomem *cmc_idpram_get_tx_buff(int dev_id); +static u32 cmc_idpram_get_tx_buff_size(int dev_id); + +static u32 cmc_idpram_get_rx_head(int dev_id); +static u32 cmc_idpram_get_rx_tail(int dev_id); +static void cmc_idpram_set_rx_head(int dev_id, u32 head); +static void cmc_idpram_set_rx_tail(int dev_id, u32 tail); +static u8 __iomem *cmc_idpram_get_rx_buff(int dev_id); +static u32 cmc_idpram_get_rx_buff_size(int dev_id); + +static u16 cmc_idpram_get_mask_req_ack(int dev_id); +static u16 cmc_idpram_get_mask_res_ack(int dev_id); +static u16 cmc_idpram_get_mask_send(int dev_id); + +static struct modemlink_dpram_control cmc_idpram_ctrl = { + .reset = cmc_idpram_reset, + + .setup_speed = cmc_idpram_setup_speed, + + .wakeup = cmc_idpram_wakeup, + .sleep = cmc_idpram_sleep, + + .clear_intr = cmc_idpram_clr_intr, + .recv_intr = cmc_idpram_recv_intr, + .send_intr = cmc_idpram_send_intr, + .recv_msg = cmc_idpram_recv_msg, + .send_msg = cmc_idpram_send_msg, + + .get_magic = cmc_idpram_get_magic, + .set_magic = cmc_idpram_set_magic, + .get_access = cmc_idpram_get_access, + .set_access = cmc_idpram_set_access, + + .get_tx_head = cmc_idpram_get_tx_head, + .get_tx_tail = cmc_idpram_get_tx_tail, + .set_tx_head = cmc_idpram_set_tx_head, + .set_tx_tail = cmc_idpram_set_tx_tail, + .get_tx_buff = cmc_idpram_get_tx_buff, + .get_tx_buff_size = cmc_idpram_get_tx_buff_size, + + .get_rx_head = cmc_idpram_get_rx_head, + .get_rx_tail = cmc_idpram_get_rx_tail, + .set_rx_head = cmc_idpram_set_rx_head, + .set_rx_tail = cmc_idpram_set_rx_tail, + .get_rx_buff = cmc_idpram_get_rx_buff, + .get_rx_buff_size = cmc_idpram_get_rx_buff_size, + + .get_mask_req_ack = cmc_idpram_get_mask_req_ack, + .get_mask_res_ack = cmc_idpram_get_mask_res_ack, + .get_mask_send = cmc_idpram_get_mask_send, + + .dp_base = NULL, + .dp_size = 0, + .dp_type = CP_IDPRAM, + .aligned = 1, + + .dpram_irq = CMC_IDPRAM_INT_IRQ_00, + .dpram_irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_RISING), + .dpram_irq_name = "CMC221_IDPRAM_IRQ", + .dpram_wlock_name = "CMC221_IDPRAM_WLOCK", + + .max_ipc_dev = MAX_CMC_IDPRAM_IPC_DEV, +}; + +/* +** UMTS target platform data +*/ +static struct modem_io_t umts_io_devices[] = { + [0] = { + .name = "umts_boot0", + .id = 0, + .format = IPC_BOOT, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [1] = { + .name = "umts_ipc0", + .id = 235, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [2] = { + .name = "umts_rfs0", + .id = 245, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [3] = { + .name = "lte_multipdp", + .id = 0, + .format = IPC_MULTI_RAW, + .io_type = IODEV_DUMMY, + .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .tx_link = LINKDEV_DPRAM, + }, + [4] = { + .name = "lte_rmnet0", + .id = 10, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .tx_link = LINKDEV_DPRAM, + }, + [5] = { + .name = "lte_rmnet1", + .id = 11, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .tx_link = LINKDEV_DPRAM, + }, + [6] = { + .name = "lte_rmnet2", + .id = 12, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .tx_link = LINKDEV_DPRAM, + }, + [7] = { + .name = "lte_rmnet3", + .id = 13, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .tx_link = LINKDEV_DPRAM, + }, + [8] = { + .name = "umts_csd", /* CS Video Telephony */ + .id = 1, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [9] = { + .name = "umts_router", /* AT Iface & Dial-up */ + .id = 25, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [10] = { + .name = "umts_dm0", /* DM Port */ + .id = 28, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [11] = { + .name = "umts_loopback_ap2cp", + .id = 30, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [12] = { + .name = "umts_loopback_cp2ap", + .id = 31, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [13] = { + .name = "umts_ramdump0", + .id = 0, + .format = IPC_RAMDUMP, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [14] = { + .name = "lte_ipc0", + .id = 235, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_USB), + }, +}; + +static int exynos_cpu_frequency_lock(void); +static int exynos_cpu_frequency_unlock(void); + +static struct modemlink_pm_data umts_link_pm_data = { + .name = "umts_link_pm", + + .gpio_link_enable = 0, + .gpio_link_active = GPIO_ACTIVE_STATE, + .gpio_link_hostwake = GPIO_IPC_HOST_WAKEUP, + .gpio_link_slavewake = GPIO_IPC_SLAVE_WAKEUP, + + .port_enable = host_port_enable, +/* + .link_reconnect = umts_link_reconnect, +*/ + .freqlock = ATOMIC_INIT(0), + .cpufreq_lock = exynos_cpu_frequency_lock, + .cpufreq_unlock = exynos_cpu_frequency_unlock, + + .autosuspend_delay_ms = 2000, + + .has_usbhub = true, +}; + +static struct modem_data umts_modem_data = { + .name = "cmc221", + + .gpio_cp_on = CP_CMC221_PMIC_PWRON, + .gpio_cp_reset = CP_CMC221_CPU_RST, + .gpio_phone_active = GPIO_LTE_ACTIVE, + + .gpio_dpram_int = GPIO_CMC_IDPRAM_INT_00, + .gpio_dpram_status = GPIO_CMC_IDPRAM_STATUS, + .gpio_dpram_wakeup = GPIO_CMC_IDPRAM_WAKEUP, + + .gpio_slave_wakeup = GPIO_IPC_SLAVE_WAKEUP, + .gpio_host_active = GPIO_ACTIVE_STATE, + .gpio_host_wakeup = GPIO_IPC_HOST_WAKEUP, + + .modem_net = UMTS_NETWORK, + .modem_type = SEC_CMC221, + .link_types = LINKTYPE(LINKDEV_DPRAM) | LINKTYPE(LINKDEV_USB), + .link_name = "cmc221_idpram", + .dpram_ctl = &cmc_idpram_ctrl, + + .num_iodevs = ARRAY_SIZE(umts_io_devices), + .iodevs = umts_io_devices, + + .link_pm_data = &umts_link_pm_data, + + .use_handover = true, + + .ipc_version = SIPC_VER_50, + .use_mif_log = true, +}; + +static struct resource umts_modem_res[] = { + [0] = { + .name = "cp_active_irq", + .start = LTE_ACTIVE_IRQ, + .end = LTE_ACTIVE_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device umts_modem = { + .name = "mif_sipc5", + .id = 1, + .num_resources = ARRAY_SIZE(umts_modem_res), + .resource = umts_modem_res, + .dev = { + .platform_data = &umts_modem_data, + }, +}; + +#define HUB_STATE_OFF 0 +void set_hsic_lpa_states(int states) +{ + int val = gpio_get_value(umts_modem_data.gpio_cp_reset); + + mif_trace("\n"); + + if (val && states == STATE_HSIC_LPA_ENTER) { + mif_info("usb3503: hub off - lpa\n"); + host_port_enable(2, 0); + *(umts_link_pm_data.p_hub_status) = HUB_STATE_OFF; + } +} + +int get_cp_active_state(void) +{ + return gpio_get_value(umts_modem_data.gpio_phone_active); +} + +static void cmc_idpram_reset(void) +{ + iowrite16(1, cmc_sfr.reset); +} + +static void cmc_idpram_setup_speed(enum dpram_speed speed) +{ + setup_dpram_speed(cmc_idpram_cfg.csn, &cmc_idpram_access_cfg[speed]); +} + +static int cmc_idpram_wakeup(void) +{ + int cnt = 0; + + gpio_set_value(umts_modem_data.gpio_dpram_wakeup, 1); + + while (!gpio_get_value(umts_modem_data.gpio_dpram_status)) { + if (cnt++ > 10) { + mif_err("ERR: gpio_dpram_status == 0\n"); + return -EAGAIN; + } + + if (in_interrupt()) + mdelay(1); + else + msleep_interruptible(1); + } + + return 0; +} + +static void cmc_idpram_sleep(void) +{ + gpio_set_value(umts_modem_data.gpio_dpram_wakeup, 0); +} + +static void cmc_idpram_clr_intr(void) +{ + iowrite16(0xFFFF, cmc_sfr.clr_int2ap); + iowrite16(0, cmc_sfr.int2ap); +} + +static u16 cmc_idpram_recv_intr(void) +{ + return ioread16(cmc_sfr.int2ap); +} + +static void cmc_idpram_send_intr(u16 irq_mask) +{ + iowrite16(irq_mask, cmc_sfr.int2cp); +} + +static u16 cmc_idpram_recv_msg(void) +{ + return ioread16(cmc_sfr.msg2ap); +} + +static void cmc_idpram_send_msg(u16 msg) +{ + iowrite16(msg, cmc_sfr.msg2cp); +} + +static u16 cmc_idpram_get_magic(void) +{ + return ioread16(cmc_ipc_map.magic); +} + +static void cmc_idpram_set_magic(u16 value) +{ + iowrite16(value, cmc_ipc_map.magic); +} + +static u16 cmc_idpram_get_access(void) +{ + return ioread16(cmc_ipc_map.access); +} + +static void cmc_idpram_set_access(u16 value) +{ + iowrite16(value, cmc_ipc_map.access); +} + +static u32 cmc_idpram_get_tx_head(int dev_id) +{ + return ioread16(cmc_ipc_map.dev[dev_id].txq.head); +} + +static u32 cmc_idpram_get_tx_tail(int dev_id) +{ + return ioread16(cmc_ipc_map.dev[dev_id].txq.tail); +} + +static void cmc_idpram_set_tx_head(int dev_id, u32 head) +{ + int cnt = 100; + u32 val = 0; + + iowrite16((u16)head, cmc_ipc_map.dev[dev_id].txq.head); + + do { + /* Check head value written */ + val = ioread16(cmc_ipc_map.dev[dev_id].txq.head); + if (val == head) + break; + + mif_err("ERR: txq.head(%d) != head(%d)\n", val, head); + + /* Write head value again */ + iowrite16((u16)head, cmc_ipc_map.dev[dev_id].txq.head); + } while (cnt--); +} + +static void cmc_idpram_set_tx_tail(int dev_id, u32 tail) +{ + int cnt = 100; + u32 val = 0; + + iowrite16((u16)tail, cmc_ipc_map.dev[dev_id].txq.tail); + + do { + /* Check tail value written */ + val = ioread16(cmc_ipc_map.dev[dev_id].txq.tail); + if (val == tail) + break; + + mif_err("ERR: txq.tail(%d) != tail(%d)\n", val, tail); + + /* Write tail value again */ + iowrite16((u16)tail, cmc_ipc_map.dev[dev_id].txq.tail); + } while (cnt--); +} + +static u8 __iomem *cmc_idpram_get_tx_buff(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].txq.buff; +} + +static u32 cmc_idpram_get_tx_buff_size(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].txq.size; +} + +static u32 cmc_idpram_get_rx_head(int dev_id) +{ + return ioread16(cmc_ipc_map.dev[dev_id].rxq.head); +} + +static u32 cmc_idpram_get_rx_tail(int dev_id) +{ + return ioread16(cmc_ipc_map.dev[dev_id].rxq.tail); +} + +static void cmc_idpram_set_rx_head(int dev_id, u32 head) +{ + int cnt = 100; + u32 val = 0; + + iowrite16((u16)head, cmc_ipc_map.dev[dev_id].rxq.head); + + do { + /* Check head value written */ + val = ioread16(cmc_ipc_map.dev[dev_id].rxq.head); + if (val == head) + break; + + mif_err("ERR: rxq.head(%d) != head(%d)\n", val, head); + + /* Write head value again */ + iowrite16((u16)head, cmc_ipc_map.dev[dev_id].rxq.head); + } while (cnt--); +} + +static void cmc_idpram_set_rx_tail(int dev_id, u32 tail) +{ + int cnt = 100; + u32 val = 0; + + iowrite16((u16)tail, cmc_ipc_map.dev[dev_id].rxq.tail); + + do { + /* Check tail value written */ + val = ioread16(cmc_ipc_map.dev[dev_id].rxq.tail); + if (val == tail) + break; + + mif_err("ERR: rxq.tail(%d) != tail(%d)\n", val, tail); + + /* Write tail value again */ + iowrite16((u16)tail, cmc_ipc_map.dev[dev_id].rxq.tail); + } while (cnt--); +} + +static u8 __iomem *cmc_idpram_get_rx_buff(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].rxq.buff; +} + +static u32 cmc_idpram_get_rx_buff_size(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].rxq.size; +} + +static u16 cmc_idpram_get_mask_req_ack(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].mask_req_ack; +} + +static u16 cmc_idpram_get_mask_res_ack(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].mask_res_ack; +} + +static u16 cmc_idpram_get_mask_send(int dev_id) +{ + return cmc_ipc_map.dev[dev_id].mask_send; +} + +/* Set dynamic environment for a modem */ +static void setup_umts_modem_env(void) +{ + /* + ** Config DPRAM control structure + */ + if (system_rev == 1 || system_rev >= 4) + cmc_idpram_cfg.csn = 0; + else + cmc_idpram_cfg.csn = 1; + + cmc_idpram_cfg.addr = SROM_CS0_BASE + (SROM_WIDTH * cmc_idpram_cfg.csn); + cmc_idpram_cfg.end = cmc_idpram_cfg.addr + cmc_idpram_cfg.size - 1; + + if (system_rev == 1 || system_rev >= 4) { + umts_modem_data.gpio_dpram_int = GPIO_CMC_IDPRAM_INT_01; + cmc_idpram_ctrl.dpram_irq = CMC_IDPRAM_INT_IRQ_01; + } +} + +static void config_umts_modem_gpio(void) +{ + int err; + unsigned gpio_cp_on = umts_modem_data.gpio_cp_on; + unsigned gpio_cp_rst = umts_modem_data.gpio_cp_reset; + unsigned gpio_pda_active = umts_modem_data.gpio_pda_active; + unsigned gpio_phone_active = umts_modem_data.gpio_phone_active; + unsigned gpio_active_state = umts_modem_data.gpio_host_active; + unsigned gpio_host_wakeup = umts_modem_data.gpio_host_wakeup; + unsigned gpio_slave_wakeup = umts_modem_data.gpio_slave_wakeup; + unsigned gpio_dpram_int = umts_modem_data.gpio_dpram_int; + unsigned gpio_dpram_status = umts_modem_data.gpio_dpram_status; + unsigned gpio_dpram_wakeup = umts_modem_data.gpio_dpram_wakeup; + + if (gpio_cp_on) { + err = gpio_request(gpio_cp_on, "CMC_ON"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "CMC_ON"); + } else { + gpio_direction_output(gpio_cp_on, 0); + s3c_gpio_setpull(gpio_cp_on, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_cp_rst) { + err = gpio_request(gpio_cp_rst, "CMC_RST"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "CMC_RST"); + } else { + gpio_direction_output(gpio_cp_rst, 0); + s3c_gpio_setpull(gpio_cp_rst, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_pda_active) { + err = gpio_request(gpio_pda_active, "PDA_ACTIVE"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "PDA_ACTIVE"); + } else { + gpio_direction_output(gpio_pda_active, 0); + s3c_gpio_setpull(gpio_pda_active, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_phone_active) { + err = gpio_request(gpio_phone_active, "CMC_ACTIVE"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "CMC_ACTIVE"); + } else { + /* Configure as a wake-up source */ + gpio_direction_input(gpio_phone_active); + s3c_gpio_setpull(gpio_phone_active, S3C_GPIO_PULL_DOWN); + s3c_gpio_cfgpin(gpio_phone_active, S3C_GPIO_SFN(0xF)); + } + } + + if (gpio_active_state) { + err = gpio_request(gpio_active_state, "CMC_ACTIVE_STATE"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_ACTIVE_STATE"); + } else { + gpio_direction_output(gpio_active_state, 0); + s3c_gpio_setpull(gpio_active_state, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_slave_wakeup) { + err = gpio_request(gpio_slave_wakeup, "CMC_SLAVE_WAKEUP"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_SLAVE_WAKEUP"); + } else { + gpio_direction_output(gpio_slave_wakeup, 0); + s3c_gpio_setpull(gpio_slave_wakeup, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_host_wakeup) { + err = gpio_request(gpio_host_wakeup, "CMC_HOST_WAKEUP"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_HOST_WAKEUP"); + } else { + /* Configure as a wake-up source */ + gpio_direction_input(gpio_host_wakeup); + s3c_gpio_setpull(gpio_host_wakeup, S3C_GPIO_PULL_DOWN); + s3c_gpio_cfgpin(gpio_host_wakeup, S3C_GPIO_SFN(0xF)); + } + } + + if (gpio_dpram_int) { + err = gpio_request(gpio_dpram_int, "CMC_DPRAM_INT"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_DPRAM_INT"); + } else { + /* Configure as a wake-up source */ + gpio_direction_input(gpio_dpram_int); + s3c_gpio_setpull(gpio_dpram_int, S3C_GPIO_PULL_NONE); + s3c_gpio_cfgpin(gpio_dpram_int, S3C_GPIO_SFN(0xF)); + } + } + + if (gpio_dpram_status) { + err = gpio_request(gpio_dpram_status, "CMC_DPRAM_STATUS"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_DPRAM_STATUS"); + } else { + gpio_direction_input(gpio_dpram_status); + s3c_gpio_setpull(gpio_dpram_status, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_dpram_wakeup) { + err = gpio_request(gpio_dpram_wakeup, "CMC_DPRAM_WAKEUP"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", + "CMC_DPRAM_WAKEUP"); + } else { + gpio_direction_output(gpio_dpram_wakeup, 1); + s3c_gpio_setpull(gpio_dpram_wakeup, S3C_GPIO_PULL_NONE); + } + } +} + +static u8 *cmc_idpram_remap_mem_region(struct sromc_cfg *cfg) +{ + int dp_addr = cfg->addr; + int dp_size = cfg->size; + u8 __iomem *dp_base; + struct dpram_ipc_cfg *ipc_map; + struct dpram_ipc_device *dev; + + /* Remap DPRAM memory region */ + dp_base = (u8 __iomem *)ioremap_nocache(dp_addr, dp_size); + if (!dp_base) { + mif_err("ERR: ioremap_nocache for dp_base fail\n"); + return NULL; + } + mif_err("DPRAM VA=0x%08X\n", (int)dp_base); + + /* Remap DPRAM SFR region */ + dp_addr += dp_size; + cmc_sfr_base = (u8 __iomem *)ioremap_nocache(dp_addr, dp_size); + if (cmc_sfr_base == NULL) { + iounmap(dp_base); + mif_err("ERR: ioremap_nocache for cmc_sfr_base fail\n"); + return NULL; + } + + cmc_sfr.int2cp = (u16 __iomem *)(cmc_sfr_base + CMC_INT2CP_REG); + cmc_sfr.int2ap = (u16 __iomem *)(cmc_sfr_base + CMC_INT2AP_REG); + cmc_sfr.clr_int2ap = (u16 __iomem *)(cmc_sfr_base + CMC_CLR_INT_REG); + cmc_sfr.reset = (u16 __iomem *)(cmc_sfr_base + CMC_RESET_REG); + cmc_sfr.msg2cp = (u16 __iomem *)(cmc_sfr_base + CMC_PUT_REG); + cmc_sfr.msg2ap = (u16 __iomem *)(cmc_sfr_base + CMC_GET_REG); + + cmc_idpram_ctrl.dp_base = (u8 __iomem *)dp_base; + cmc_idpram_ctrl.dp_size = dp_size; + + /* Map for IPC */ + ipc_map = (struct dpram_ipc_cfg *)dp_base; + + /* Magic code and access enable fields */ + cmc_ipc_map.magic = (u16 __iomem *)&ipc_map->magic; + cmc_ipc_map.access = (u16 __iomem *)&ipc_map->access; + + /* FMT */ + dev = &cmc_ipc_map.dev[IPC_FMT]; + + strcpy(dev->name, "FMT"); + dev->id = IPC_FMT; + + dev->txq.head = (u16 __iomem *)&ipc_map->fmt_tx_head; + dev->txq.tail = (u16 __iomem *)&ipc_map->fmt_tx_tail; + dev->txq.buff = (u8 __iomem *)&ipc_map->fmt_tx_buff[0]; + dev->txq.size = DP_FMT_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&ipc_map->fmt_rx_head; + dev->rxq.tail = (u16 __iomem *)&ipc_map->fmt_rx_tail; + dev->rxq.buff = (u8 __iomem *)&ipc_map->fmt_rx_buff[0]; + dev->rxq.size = DP_FMT_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_F; + dev->mask_res_ack = INT_MASK_RES_ACK_F; + dev->mask_send = INT_MASK_SEND_F; + + /* RAW */ + dev = &cmc_ipc_map.dev[IPC_RAW]; + + strcpy(dev->name, "RAW"); + dev->id = IPC_RAW; + + dev->txq.head = (u16 __iomem *)&ipc_map->raw_tx_head; + dev->txq.tail = (u16 __iomem *)&ipc_map->raw_tx_tail; + dev->txq.buff = (u8 __iomem *)&ipc_map->raw_tx_buff[0]; + dev->txq.size = DP_RAW_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&ipc_map->raw_rx_head; + dev->rxq.tail = (u16 __iomem *)&ipc_map->raw_rx_tail; + dev->rxq.buff = (u8 __iomem *)&ipc_map->raw_rx_buff[0]; + dev->rxq.size = DP_RAW_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_R; + dev->mask_res_ack = INT_MASK_RES_ACK_R; + dev->mask_send = INT_MASK_SEND_R; + + return dp_base; +} +#endif + +#ifdef CONFIG_CDMA_MODEM_CBP72 +static struct sromc_cfg cbp_edpram_cfg = { + .attr = SROMC_DATA_16 | SROMC_BYTE_EN, + .size = CBP_EDPRAM_SIZE, +}; + +static struct sromc_access_cfg cbp_edpram_access_cfg[] = { + [DPRAM_SPEED_LOW] = { + .tacs = 0x00 << 28, + .tcos = 0x00 << 24, + .tacc = 0x0F << 16, + .tcoh = 0x00 << 12, + .tcah = 0x00 << 8, + .tacp = 0x00 << 4, + .pmc = 0x00 << 0, + }, +}; + +/* + magic_code + + access_enable + + fmt_tx_head + fmt_tx_tail + fmt_tx_buff + + raw_tx_head + raw_tx_tail + raw_tx_buff + + fmt_rx_head + fmt_rx_tail + fmt_rx_buff + + raw_rx_head + raw_rx_tail + raw_rx_buff + + mbx_cp2ap + + mbx_ap2cp + = 2 + + 2 + + 2 + 2 + 1336 + + 2 + 2 + 4564 + + 2 + 2 + 1336 + + 2 + 2 + 9124 + + 2 + + 2 + = 16384 +*/ + +#define CBP_DP_FMT_TX_BUFF_SZ 1336 +#define CBP_DP_RAW_TX_BUFF_SZ 4564 +#define CBP_DP_FMT_RX_BUFF_SZ 1336 +#define CBP_DP_RAW_RX_BUFF_SZ 9124 + +#define MAX_CBP_EDPRAM_IPC_DEV (IPC_RAW + 1) /* FMT, RAW */ + +struct cbp_edpram_ipc_cfg { + u16 magic; + u16 access; + + u16 fmt_tx_head; + u16 fmt_tx_tail; + u8 fmt_tx_buff[CBP_DP_FMT_TX_BUFF_SZ]; + + u16 raw_tx_head; + u16 raw_tx_tail; + u8 raw_tx_buff[CBP_DP_RAW_TX_BUFF_SZ]; + + u16 fmt_rx_head; + u16 fmt_rx_tail; + u8 fmt_rx_buff[CBP_DP_FMT_RX_BUFF_SZ]; + + u16 raw_rx_head; + u16 raw_rx_tail; + u8 raw_rx_buff[CBP_DP_RAW_RX_BUFF_SZ]; + + u16 mbx_cp2ap; + u16 mbx_ap2cp; +}; + +static struct dpram_ipc_map cbp_ipc_map; + +static void cbp_edpram_reset(void); +static void cbp_edpram_clr_intr(void); +static u16 cbp_edpram_recv_intr(void); +static void cbp_edpram_send_intr(u16 irq_mask); +static u16 cbp_edpram_recv_msg(void); +static void cbp_edpram_send_msg(u16 msg); + +static u16 cbp_edpram_get_magic(void); +static void cbp_edpram_set_magic(u16 value); +static u16 cbp_edpram_get_access(void); +static void cbp_edpram_set_access(u16 value); + +static u32 cbp_edpram_get_tx_head(int dev_id); +static u32 cbp_edpram_get_tx_tail(int dev_id); +static void cbp_edpram_set_tx_head(int dev_id, u32 head); +static void cbp_edpram_set_tx_tail(int dev_id, u32 tail); +static u8 __iomem *cbp_edpram_get_tx_buff(int dev_id); +static u32 cbp_edpram_get_tx_buff_size(int dev_id); + +static u32 cbp_edpram_get_rx_head(int dev_id); +static u32 cbp_edpram_get_rx_tail(int dev_id); +static void cbp_edpram_set_rx_head(int dev_id, u32 head); +static void cbp_edpram_set_rx_tail(int dev_id, u32 tail); +static u8 __iomem *cbp_edpram_get_rx_buff(int dev_id); +static u32 cbp_edpram_get_rx_buff_size(int dev_id); + +static u16 cbp_edpram_get_mask_req_ack(int dev_id); +static u16 cbp_edpram_get_mask_res_ack(int dev_id); +static u16 cbp_edpram_get_mask_send(int dev_id); + +static struct modemlink_dpram_control cbp_edpram_ctrl = { + .reset = cbp_edpram_reset, + + .clear_intr = cbp_edpram_clr_intr, + .recv_intr = cbp_edpram_recv_intr, + .send_intr = cbp_edpram_send_intr, + .recv_msg = cbp_edpram_recv_msg, + .send_msg = cbp_edpram_send_msg, + + .get_magic = cbp_edpram_get_magic, + .set_magic = cbp_edpram_set_magic, + .get_access = cbp_edpram_get_access, + .set_access = cbp_edpram_set_access, + + .get_tx_head = cbp_edpram_get_tx_head, + .get_tx_tail = cbp_edpram_get_tx_tail, + .set_tx_head = cbp_edpram_set_tx_head, + .set_tx_tail = cbp_edpram_set_tx_tail, + .get_tx_buff = cbp_edpram_get_tx_buff, + .get_tx_buff_size = cbp_edpram_get_tx_buff_size, + + .get_rx_head = cbp_edpram_get_rx_head, + .get_rx_tail = cbp_edpram_get_rx_tail, + .set_rx_head = cbp_edpram_set_rx_head, + .set_rx_tail = cbp_edpram_set_rx_tail, + .get_rx_buff = cbp_edpram_get_rx_buff, + .get_rx_buff_size = cbp_edpram_get_rx_buff_size, + + .get_mask_req_ack = cbp_edpram_get_mask_req_ack, + .get_mask_res_ack = cbp_edpram_get_mask_res_ack, + .get_mask_send = cbp_edpram_get_mask_send, + + .dp_base = NULL, + .dp_size = 0, + .dp_type = EXT_DPRAM, + .aligned = 1, + + .dpram_irq = CBP_DPRAM_INT_IRQ_00, + .dpram_irq_flags = (IRQF_NO_SUSPEND | IRQF_TRIGGER_FALLING), + .dpram_irq_name = "CBP72_EDPRAM_IRQ", + .dpram_wlock_name = "CBP72_EDPRAM_WLOCK", + + .max_ipc_dev = MAX_CBP_EDPRAM_IPC_DEV, +}; + +/* +** CDMA target platform data +*/ +static struct modem_io_t cdma_io_devices[] = { + [0] = { + .name = "cdma_boot0", + .id = 0, + .format = IPC_BOOT, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [1] = { + .name = "cdma_ipc0", + .id = 235, + .format = IPC_FMT, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [2] = { + .name = "cdma_rfs0", + .id = 245, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [3] = { + .name = "cdma_multipdp", + .id = 0, + .format = IPC_MULTI_RAW, + .io_type = IODEV_DUMMY, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [4] = { + .name = "cdma_rmnet0", + .id = 10, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [5] = { + .name = "cdma_rmnet1", + .id = 11, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [6] = { + .name = "cdma_rmnet2", + .id = 12, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [7] = { + .name = "cdma_rmnet3", + .id = 13, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [8] = { + .name = "cdma_rmnet4", + .id = 7, + .format = IPC_RAW, + .io_type = IODEV_NET, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [9] = { + .name = "cdma_rmnet5", /* DM Port IO device */ + .id = 26, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [10] = { + .name = "cdma_rmnet6", /* AT CMD IO device */ + .id = 17, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [11] = { + .name = "cdma_ramdump0", + .id = 0, + .format = IPC_RAMDUMP, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, + [12] = { + .name = "cdma_cplog", + .id = 29, + .format = IPC_RAW, + .io_type = IODEV_MISC, + .links = LINKTYPE(LINKDEV_DPRAM), + }, +}; + +static struct modem_data cdma_modem_data = { + .name = "cbp7.2", + + .gpio_cp_on = GPIO_CBP_PMIC_PWRON, + .gpio_cp_off = GPIO_CBP_PS_HOLD_OFF, + .gpio_cp_reset = GPIO_CBP_CP_RST, + .gpio_pda_active = GPIO_PDA_ACTIVE, + .gpio_phone_active = GPIO_CBP_PHONE_ACTIVE, + + .gpio_dpram_int = GPIO_CBP_DPRAM_INT_00, + + .modem_net = CDMA_NETWORK, + .modem_type = VIA_CBP72, + .link_types = LINKTYPE(LINKDEV_DPRAM), + .link_name = "cbp72_edpram", + .dpram_ctl = &cbp_edpram_ctrl, + + .num_iodevs = ARRAY_SIZE(cdma_io_devices), + .iodevs = cdma_io_devices, + + .use_handover = true, + + .ipc_version = SIPC_VER_50, +}; + +static struct resource cdma_modem_res[] = { + [0] = { + .name = "cp_active_irq", + .start = CBP_PHONE_ACTIVE_IRQ, + .end = CBP_PHONE_ACTIVE_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device cdma_modem = { + .name = "mif_sipc5", + .id = 2, + .num_resources = ARRAY_SIZE(cdma_modem_res), + .resource = cdma_modem_res, + .dev = { + .platform_data = &cdma_modem_data, + }, +}; + +static void cbp_edpram_reset(void) +{ + return; +} + +static void cbp_edpram_clr_intr(void) +{ + ioread16(cbp_ipc_map.mbx_cp2ap); +} + +static u16 cbp_edpram_recv_intr(void) +{ + return ioread16(cbp_ipc_map.mbx_cp2ap); +} + +static void cbp_edpram_send_intr(u16 irq_mask) +{ + iowrite16(irq_mask, cbp_ipc_map.mbx_ap2cp); +} + +static u16 cbp_edpram_recv_msg(void) +{ + return ioread16(cbp_ipc_map.mbx_cp2ap); +} + +static void cbp_edpram_send_msg(u16 msg) +{ + iowrite16(msg, cbp_ipc_map.mbx_ap2cp); +} + +static u16 cbp_edpram_get_magic(void) +{ + return ioread16(cbp_ipc_map.magic); +} + +static void cbp_edpram_set_magic(u16 value) +{ + iowrite16(value, cbp_ipc_map.magic); +} + +static u16 cbp_edpram_get_access(void) +{ + return ioread16(cbp_ipc_map.access); +} + +static void cbp_edpram_set_access(u16 value) +{ + iowrite16(value, cbp_ipc_map.access); +} + +static u32 cbp_edpram_get_tx_head(int dev_id) +{ + return ioread16(cbp_ipc_map.dev[dev_id].txq.head); +} + +static u32 cbp_edpram_get_tx_tail(int dev_id) +{ + return ioread16(cbp_ipc_map.dev[dev_id].txq.tail); +} + +static void cbp_edpram_set_tx_head(int dev_id, u32 head) +{ + iowrite16((u16)head, cbp_ipc_map.dev[dev_id].txq.head); +} + +static void cbp_edpram_set_tx_tail(int dev_id, u32 tail) +{ + iowrite16((u16)tail, cbp_ipc_map.dev[dev_id].txq.tail); +} + +static u8 __iomem *cbp_edpram_get_tx_buff(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].txq.buff; +} + +static u32 cbp_edpram_get_tx_buff_size(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].txq.size; +} + +static u32 cbp_edpram_get_rx_head(int dev_id) +{ + return ioread16(cbp_ipc_map.dev[dev_id].rxq.head); +} + +static u32 cbp_edpram_get_rx_tail(int dev_id) +{ + return ioread16(cbp_ipc_map.dev[dev_id].rxq.tail); +} + +static void cbp_edpram_set_rx_head(int dev_id, u32 head) +{ + return iowrite16((u16)head, cbp_ipc_map.dev[dev_id].rxq.head); +} + +static void cbp_edpram_set_rx_tail(int dev_id, u32 tail) +{ + return iowrite16((u16)tail, cbp_ipc_map.dev[dev_id].rxq.tail); +} + +static u8 __iomem *cbp_edpram_get_rx_buff(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].rxq.buff; +} + +static u32 cbp_edpram_get_rx_buff_size(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].rxq.size; +} + +static u16 cbp_edpram_get_mask_req_ack(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].mask_req_ack; +} + +static u16 cbp_edpram_get_mask_res_ack(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].mask_res_ack; +} + +static u16 cbp_edpram_get_mask_send(int dev_id) +{ + return cbp_ipc_map.dev[dev_id].mask_send; +} + +/* Set dynamic environment for a modem */ +static void setup_cdma_modem_env(void) +{ + /* + ** Config DPRAM control structure + */ + if (system_rev == 1 || system_rev >= 4) + cbp_edpram_cfg.csn = 1; + else + cbp_edpram_cfg.csn = 0; + + cbp_edpram_cfg.addr = SROM_CS0_BASE + (SROM_WIDTH * cbp_edpram_cfg.csn); + cbp_edpram_cfg.end = cbp_edpram_cfg.addr + cbp_edpram_cfg.size - 1; + + if (system_rev == 1 || system_rev >= 4) { + cdma_modem_data.gpio_dpram_int = GPIO_CBP_DPRAM_INT_01; + cbp_edpram_ctrl.dpram_irq = CBP_DPRAM_INT_IRQ_01; + } +} + +static void config_cdma_modem_gpio(void) +{ + int err; + unsigned gpio_boot_sel = GPIO_CBP_BOOT_SEL; + unsigned gpio_cp_on = cdma_modem_data.gpio_cp_on; + unsigned gpio_cp_off = cdma_modem_data.gpio_cp_off; + unsigned gpio_cp_rst = cdma_modem_data.gpio_cp_reset; + unsigned gpio_pda_active = cdma_modem_data.gpio_pda_active; + unsigned gpio_phone_active = cdma_modem_data.gpio_phone_active; + unsigned gpio_dpram_int = cdma_modem_data.gpio_dpram_int; + + pr_info("[MDM] <%s>\n", __func__); + + if (gpio_boot_sel) { + err = gpio_request(gpio_boot_sel, "CBP_BOOT_SEL"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_BOOT_SEL"); + } else { + gpio_direction_output(gpio_boot_sel, 0); + s3c_gpio_setpull(gpio_boot_sel, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_cp_on) { + err = gpio_request(gpio_cp_on, "CBP_ON"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_ON"); + } else { + gpio_direction_output(gpio_cp_on, 0); + s3c_gpio_setpull(gpio_cp_on, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_cp_off) { + err = gpio_request(gpio_cp_off, "CBP_OFF"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_OFF"); + } else { + gpio_direction_output(gpio_cp_off, 1); + s3c_gpio_setpull(gpio_cp_off, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_cp_rst) { + err = gpio_request(gpio_cp_rst, "CBP_RST"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_RST"); + } else { + gpio_direction_output(gpio_cp_rst, 0); + s3c_gpio_setpull(gpio_cp_rst, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_pda_active) { + err = gpio_request(gpio_pda_active, "PDA_ACTIVE"); + if (err) { + pr_err("fail to request gpio %s\n", "PDA_ACTIVE"); + } else { + gpio_direction_output(gpio_pda_active, 0); + s3c_gpio_setpull(gpio_pda_active, S3C_GPIO_PULL_NONE); + } + } + + if (gpio_phone_active) { + err = gpio_request(gpio_phone_active, "CBP_ACTIVE"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_ACTIVE"); + } else { + /* Configure as a wake-up source */ + gpio_direction_input(gpio_phone_active); + s3c_gpio_setpull(gpio_phone_active, S3C_GPIO_PULL_NONE); + s3c_gpio_cfgpin(gpio_phone_active, S3C_GPIO_SFN(0xF)); + } + } + + if (gpio_dpram_int) { + err = gpio_request(gpio_dpram_int, "CBP_DPRAM_INT"); + if (err) { + pr_err("fail to request gpio %s\n", "CBP_DPRAM_INT"); + } else { + /* Configure as a wake-up source */ + gpio_direction_input(gpio_dpram_int); + s3c_gpio_setpull(gpio_dpram_int, S3C_GPIO_PULL_NONE); + s3c_gpio_cfgpin(gpio_dpram_int, S3C_GPIO_SFN(0xF)); + } + } + + /* set low unused gpios between AP and CP */ + err = gpio_request(GPIO_FLM_RXD, "FLM_RXD"); + if (err) + pr_err(LOG_TAG "fail to request gpio %s : %d\n", "FLM_RXD", + err); + else { + gpio_direction_input(GPIO_FLM_RXD); + s3c_gpio_setpull(GPIO_FLM_RXD, S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(GPIO_FLM_RXD, S3C_GPIO_SFN(2)); + } + + err = gpio_request(GPIO_FLM_TXD, "FLM_TXD"); + if (err) + pr_err(LOG_TAG "fail to request gpio %s : %d\n", "FLM_TXD", + err); + else { + gpio_direction_input(GPIO_FLM_TXD); + s3c_gpio_setpull(GPIO_FLM_TXD, S3C_GPIO_PULL_NONE); + s3c_gpio_cfgpin(GPIO_FLM_TXD, S3C_GPIO_SFN(2)); + } +} + +static u8 *cbp_edpram_remap_mem_region(struct sromc_cfg *cfg) +{ + int dp_addr = 0; + int dp_size = 0; + u8 __iomem *dp_base = NULL; + struct cbp_edpram_ipc_cfg *ipc_map = NULL; + struct dpram_ipc_device *dev = NULL; + + dp_addr = cfg->addr; + dp_size = cfg->size; + dp_base = (u8 *)ioremap_nocache(dp_addr, dp_size); + if (!dp_base) { + pr_err("[MDM] <%s> dpram base ioremap fail\n", __func__); + return NULL; + } + pr_info("[MDM] <%s> DPRAM VA=0x%08X\n", __func__, (int)dp_base); + + cbp_edpram_ctrl.dp_base = (u8 __iomem *)dp_base; + cbp_edpram_ctrl.dp_size = dp_size; + + /* Map for IPC */ + ipc_map = (struct cbp_edpram_ipc_cfg *)dp_base; + + /* Magic code and access enable fields */ + cbp_ipc_map.magic = (u16 __iomem *)&ipc_map->magic; + cbp_ipc_map.access = (u16 __iomem *)&ipc_map->access; + + /* FMT */ + dev = &cbp_ipc_map.dev[IPC_FMT]; + + strcpy(dev->name, "FMT"); + dev->id = IPC_FMT; + + dev->txq.head = (u16 __iomem *)&ipc_map->fmt_tx_head; + dev->txq.tail = (u16 __iomem *)&ipc_map->fmt_tx_tail; + dev->txq.buff = (u8 __iomem *)&ipc_map->fmt_tx_buff[0]; + dev->txq.size = CBP_DP_FMT_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&ipc_map->fmt_rx_head; + dev->rxq.tail = (u16 __iomem *)&ipc_map->fmt_rx_tail; + dev->rxq.buff = (u8 __iomem *)&ipc_map->fmt_rx_buff[0]; + dev->rxq.size = CBP_DP_FMT_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_F; + dev->mask_res_ack = INT_MASK_RES_ACK_F; + dev->mask_send = INT_MASK_SEND_F; + + /* RAW */ + dev = &cbp_ipc_map.dev[IPC_RAW]; + + strcpy(dev->name, "RAW"); + dev->id = IPC_RAW; + + dev->txq.head = (u16 __iomem *)&ipc_map->raw_tx_head; + dev->txq.tail = (u16 __iomem *)&ipc_map->raw_tx_tail; + dev->txq.buff = (u8 __iomem *)&ipc_map->raw_tx_buff[0]; + dev->txq.size = CBP_DP_RAW_TX_BUFF_SZ; + + dev->rxq.head = (u16 __iomem *)&ipc_map->raw_rx_head; + dev->rxq.tail = (u16 __iomem *)&ipc_map->raw_rx_tail; + dev->rxq.buff = (u8 __iomem *)&ipc_map->raw_rx_buff[0]; + dev->rxq.size = CBP_DP_RAW_RX_BUFF_SZ; + + dev->mask_req_ack = INT_MASK_REQ_ACK_R; + dev->mask_res_ack = INT_MASK_RES_ACK_R; + dev->mask_send = INT_MASK_SEND_R; + + /* Mailboxes */ + cbp_ipc_map.mbx_ap2cp = (u16 __iomem *)&ipc_map->mbx_ap2cp; + cbp_ipc_map.mbx_cp2ap = (u16 __iomem *)&ipc_map->mbx_cp2ap; + + return dp_base; +} +#endif + +/** + * DPRAM GPIO settings + * + * SROM_NUM_ADDR_BITS value indicate the address line number or + * the mux/demux dpram type. if you want to set mux mode, define the + * SROM_NUM_ADDR_BITS to zero. + * + * for CMC22x + * CMC22x has 16KB + a SFR register address. + * It used 14 bits (13bits for 16KB word address and 1 bit for SFR + * register) + */ +static void config_dpram_port_gpio(void) +{ + int addr_bits = SROM_NUM_ADDR_BITS; + + mif_info("address line = %d bits\n", addr_bits); + + /* + ** Config DPRAM address/data GPIO pins + */ + + /* Set GPIO for address bus (13 ~ 14 bits) */ + switch (addr_bits) { + case 0: + break; + + case 13 ... 14: + s3c_gpio_cfgrange_nopull(GPIO_SROM_ADDR_BUS_LOW, + EXYNOS4_GPIO_Y3_NR, S3C_GPIO_SFN(2)); + s3c_gpio_cfgrange_nopull(GPIO_SROM_ADDR_BUS_HIGH, + (addr_bits - EXYNOS4_GPIO_Y3_NR), S3C_GPIO_SFN(2)); + break; + + default: + mif_err("ERR: invalid addr_bits!!!\n"); + return; + } + + /* Set GPIO for data bus (16 bits) */ + s3c_gpio_cfgrange_nopull(GPIO_SROM_DATA_BUS_LOW, 8, S3C_GPIO_SFN(2)); + s3c_gpio_cfgrange_nopull(GPIO_SROM_DATA_BUS_HIGH, 8, S3C_GPIO_SFN(2)); + + /* Setup SROMC CSn pins */ + s3c_gpio_cfgpin(GPIO_DPRAM_CSN0, S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin((GPIO_DPRAM_CSN0 + 1), S3C_GPIO_SFN(2)); + + /* Config OEn, WEn */ + s3c_gpio_cfgpin(GPIO_DPRAM_REN, S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(GPIO_DPRAM_WEN, S3C_GPIO_SFN(2)); + + /* Config LBn, UBn */ + s3c_gpio_cfgpin(GPIO_DPRAM_LBN, S3C_GPIO_SFN(2)); + s3c_gpio_cfgpin(GPIO_DPRAM_UBN, S3C_GPIO_SFN(2)); +} + +static void init_sromc(void) +{ + struct clk *clk = NULL; + + /* SROMC clk enable */ + clk = clk_get(NULL, "sromc"); + if (!clk) { + mif_err("ERR: SROMC clock gate fail\n"); + return; + } + clk_enable(clk); +} + +static void setup_sromc +( + unsigned csn, + struct sromc_cfg *cfg, + struct sromc_access_cfg *acc_cfg +) +{ + unsigned bw = 0; /* Bus width and wait control */ + unsigned bc = 0; /* Vank control */ + void __iomem *bank_sfr = S5P_SROM_BC0 + (4 * csn); + + mif_err("SROMC settings for CS%d...\n", csn); + + bw = __raw_readl(S5P_SROM_BW); + bc = __raw_readl(bank_sfr); + mif_err("Old SROMC settings = BW(0x%08X) BC%d(0x%08X)\n", bw, csn, bc); + + /* Set the BW control field for the CSn */ + bw &= ~(SROMC_MASK << (csn << 2)); + bw |= (cfg->attr << (csn << 2)); + writel(bw, S5P_SROM_BW); + + /* Set SROMC memory access timing for the CSn */ + bc = acc_cfg->tacs | acc_cfg->tcos | acc_cfg->tacc | + acc_cfg->tcoh | acc_cfg->tcah | acc_cfg->tacp | acc_cfg->pmc; + + writel(bc, bank_sfr); + + /* Verify SROMC settings */ + bw = __raw_readl(S5P_SROM_BW); + bc = __raw_readl(bank_sfr); + mif_err("New SROMC settings = BW(0x%08X) BC%d(0x%08X)\n", bw, csn, bc); +} + +static void setup_dpram_speed(unsigned csn, struct sromc_access_cfg *acc_cfg) +{ + void __iomem *bank_sfr = S5P_SROM_BC0 + (4 * csn); + unsigned bc = 0; + + bc = __raw_readl(bank_sfr); + mif_info("Old CS%d setting = 0x%08X\n", csn, bc); + + /* SROMC memory access timing setting */ + bc = acc_cfg->tacs | acc_cfg->tcos | acc_cfg->tacc | + acc_cfg->tcoh | acc_cfg->tcah | acc_cfg->tacp | acc_cfg->pmc; + writel(bc, bank_sfr); + + bc = __raw_readl(bank_sfr); + mif_info("New CS%d setting = 0x%08X\n", csn, bc); +} + +static int __init init_modem(void) +{ + struct sromc_cfg *cfg = NULL; + struct sromc_access_cfg *acc_cfg = NULL; + + mif_err("System Revision = %d\n", system_rev); + + setup_umts_modem_env(); + setup_cdma_modem_env(); + + config_dpram_port_gpio(); + + config_umts_modem_gpio(); + config_cdma_modem_gpio(); + + init_sromc(); + + cfg = &cmc_idpram_cfg; + acc_cfg = &cmc_idpram_access_cfg[DPRAM_SPEED_LOW]; + setup_sromc(cfg->csn, cfg, acc_cfg); + + cfg = &cbp_edpram_cfg; + acc_cfg = &cbp_edpram_access_cfg[DPRAM_SPEED_LOW]; + setup_sromc(cfg->csn, cfg, acc_cfg); + + if (!cmc_idpram_remap_mem_region(&cmc_idpram_cfg)) + return -1; + platform_device_register(&umts_modem); + + if (!cbp_edpram_remap_mem_region(&cbp_edpram_cfg)) + return -1; + platform_device_register(&cdma_modem); + + return 0; +} +late_initcall(init_modem); +/*device_initcall(init_modem);*/ + +#ifdef CONFIG_USBHUB_USB3503 +static int (*usbhub_set_mode)(struct usb3503_hubctl *, int); +static struct usb3503_hubctl *usbhub_ctl; + +#ifdef CONFIG_EXYNOS4_CPUFREQ +static int exynos_cpu_frequency_lock(void) +{ + unsigned int level, freq = 700; + + if (atomic_read(&umts_link_pm_data.freqlock) == 0) { + if (exynos_cpufreq_get_level(freq * 1000, &level)) { + mif_err("ERR: exynos_cpufreq_get_level fail\n"); + return -EINVAL; + } + + if (exynos_cpufreq_lock(DVFS_LOCK_ID_USB_IF, level)) { + mif_err("ERR: exynos_cpufreq_lock fail\n"); + return -EINVAL; + } + + atomic_set(&umts_link_pm_data.freqlock, 1); + mif_debug("<%d> %d MHz\n", level, freq); + } + return 0; +} + +static int exynos_cpu_frequency_unlock(void) +{ + if (atomic_read(&umts_link_pm_data.freqlock) == 1) { + exynos_cpufreq_lock_free(DVFS_LOCK_ID_USB_IF); + atomic_set(&umts_link_pm_data.freqlock, 0); + mif_debug("\n"); + } + return 0; +} +#else +static int exynos_cpu_frequency_lock(void) +{ + return 0; +} + +static int exynos_cpu_frequency_unlock(void) +{ + return 0; +} +#endif + +void set_host_states(struct platform_device *pdev, int type) +{ +} + +static int usb3503_hub_handler(void (*set_mode)(void), void *ctl) +{ + if (!set_mode || !ctl) + return -EINVAL; + + usbhub_set_mode = (int (*)(struct usb3503_hubctl *, int))set_mode; + usbhub_ctl = (struct usb3503_hubctl *)ctl; + + mif_info("set_mode(%pF)\n", set_mode); + + return 0; +} + +static int usb3503_hw_config(void) +{ + int err; + + err = gpio_request(GPIO_USB_HUB_RST, "HUB_RST"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "HUB_RST"); + } else { + gpio_direction_output(GPIO_USB_HUB_RST, 0); + s3c_gpio_setpull(GPIO_USB_HUB_RST, S3C_GPIO_PULL_NONE); + } + s5p_gpio_set_drvstr(GPIO_USB_HUB_RST, S5P_GPIO_DRVSTR_LV1); + /* need to check drvstr 1 or 2 */ + + /* for USB3503 26Mhz Reference clock setting */ + err = gpio_request(GPIO_USB_HUB_INT, "HUB_INT"); + if (err) { + mif_err("ERR: fail to request gpio %s\n", "HUB_INT"); + } else { + gpio_direction_output(GPIO_USB_HUB_INT, 1); + s3c_gpio_setpull(GPIO_USB_HUB_INT, S3C_GPIO_PULL_NONE); + } + + return 0; +} + +static int usb3503_reset_n(int val) +{ + gpio_set_value(GPIO_USB_HUB_RST, 0); + + /* hub off from cpuidle(LPA), skip the msleep schedule*/ + if (val) { + msleep(20); + mif_info("val = %d\n", gpio_get_value(GPIO_USB_HUB_RST)); + + gpio_set_value(GPIO_USB_HUB_RST, !!val); + + mif_info("val = %d\n", gpio_get_value(GPIO_USB_HUB_RST)); + udelay(5); /* need it ?*/ + } + return 0; +} + +static struct usb3503_platform_data usb3503_pdata = { + .initial_mode = USB3503_MODE_STANDBY, + .reset_n = usb3503_reset_n, + .register_hub_handler = usb3503_hub_handler, + .port_enable = host_port_enable, +}; + +static struct i2c_board_info i2c_devs20_emul[] __initdata = { + { + I2C_BOARD_INFO(USB3503_I2C_NAME, 0x08), + .platform_data = &usb3503_pdata, + }, +}; + +/* I2C20_EMUL */ +static struct i2c_gpio_platform_data i2c20_platdata = { + .sda_pin = GPIO_USB_HUB_SDA, + .scl_pin = GPIO_USB_HUB_SCL, + /*FIXME: need to timming tunning... */ + .udelay = 20, +}; + +static struct platform_device s3c_device_i2c20 = { + .name = "i2c-gpio", + .id = 20, + .dev.platform_data = &i2c20_platdata, +}; + +static int __init init_usbhub(void) +{ + usb3503_hw_config(); + i2c_register_board_info(20, i2c_devs20_emul, + ARRAY_SIZE(i2c_devs20_emul)); + + platform_device_register(&s3c_device_i2c20); + return 0; +} + +device_initcall(init_usbhub); + +static int host_port_enable(int port, int enable) +{ + int err; + + mif_info("port(%d) control(%d)\n", port, enable); + + if (enable) { + err = usbhub_set_mode(usbhub_ctl, USB3503_MODE_HUB); + if (err < 0) { + mif_err("ERR: hub on fail\n"); + goto exit; + } + err = s5p_ehci_port_control(&s5p_device_ehci, port, 1); + if (err < 0) { + mif_err("ERR: port(%d) enable fail\n", port); + goto exit; + } + } else { + err = s5p_ehci_port_control(&s5p_device_ehci, port, 0); + if (err < 0) { + mif_err("ERR: port(%d) enable fail\n", port); + goto exit; + } + err = usbhub_set_mode(usbhub_ctl, USB3503_MODE_STANDBY); + if (err < 0) { + mif_err("ERR: hub off fail\n"); + goto exit; + } + } + + err = gpio_direction_output(umts_modem_data.gpio_host_active, enable); + mif_info("active state err(%d), en(%d), level(%d)\n", + err, enable, gpio_get_value(umts_modem_data.gpio_host_active)); + +exit: + return err; +} +#else +void set_host_states(struct platform_device *pdev, int type) +{ + if (active_ctl.gpio_initialized) { + mif_err("<%s> Active States =%d, %s\n", pdev->name, type); + gpio_direction_output(umts_link_pm_data.gpio_link_active, type); + } else { + active_ctl.gpio_request_host_active = 1; + } +} +#endif + |