From 2f3ec3402714d2ad20475b016487c7559ccba383 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:24 +0000 Subject: tegra: usb: set USB_PORTS_MAX to correct value Both Tegra20 and Tegra30 have a max of 3 USB controllers. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index 1bccf2b0b2..f151fb2c3b 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -44,7 +44,7 @@ #endif enum { - USB_PORTS_MAX = 4, /* Maximum ports we allow */ + USB_PORTS_MAX = 3, /* Maximum ports we allow */ }; /* Parameters we need for USB */ -- cgit From b0bbab8a149ad4c3f764fa7ecff79788769cab99 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:25 +0000 Subject: tegra: usb: make controller init functions more self contained There is no need to pass around all those parameters. The init functions are able to easily extract all the needed setup info on their own. This allows to move out the controller init into ehci_hcd_init later on, without having to save away global state for later use and thus bloating the file global state. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/usb.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index f151fb2c3b..07c1adefe3 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -198,11 +198,12 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) } /* set up the UTMI USB controller with the parameters provided */ -static int init_utmi_usb_controller(struct fdt_usb *config, - struct usb_ctlr *usbctlr, const u32 timing[]) +static int init_utmi_usb_controller(struct fdt_usb *config) { u32 val; int loop_count; + const unsigned *timing; + struct usb_ctlr *usbctlr = config->reg; clock_enable(config->periph_id); @@ -229,6 +230,8 @@ static int init_utmi_usb_controller(struct fdt_usb *config, * PLL Delay CONFIGURATION settings. The following parameters control * the bring up of the plls. */ + timing = usb_pll[clock_get_osc_freq()]; + val = readl(&usbctlr->utmip_misc_cfg1); clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK, timing[PARAM_STABLE_COUNT] << UTMIP_PLLU_STABLE_COUNT_SHIFT); @@ -331,12 +334,12 @@ static int init_utmi_usb_controller(struct fdt_usb *config, #endif /* set up the ULPI USB controller with the parameters provided */ -static int init_ulpi_usb_controller(struct fdt_usb *config, - struct usb_ctlr *usbctlr) +static int init_ulpi_usb_controller(struct fdt_usb *config) { u32 val; int loop_count; struct ulpi_viewport ulpi_vp; + struct usb_ctlr *usbctlr = config->reg; /* set up ULPI reference clock on pllp_out4 */ clock_enable(PERIPH_ID_DEV2_OUT); @@ -408,8 +411,7 @@ static int init_ulpi_usb_controller(struct fdt_usb *config, return 0; } #else -static int init_ulpi_usb_controller(struct fdt_usb *config, - struct usb_ctlr *usbctlr) +static int init_ulpi_usb_controller(struct fdt_usb *config) { printf("No code to set up ULPI controller, please enable" "CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT"); @@ -430,22 +432,20 @@ static void config_clock(const u32 timing[]) * @param config USB port configuration * @return 0 if ok, -1 if error (too many ports) */ -static int add_port(struct fdt_usb *config, const u32 timing[]) +static int add_port(struct fdt_usb *config) { - struct usb_ctlr *usbctlr = config->reg; - if (port_count == USB_PORTS_MAX) { printf("tegrausb: Cannot register more than %d ports\n", USB_PORTS_MAX); return -1; } - if (config->utmi && init_utmi_usb_controller(config, usbctlr, timing)) { + if (config->utmi && init_utmi_usb_controller(config)) { printf("tegrausb: Cannot init port\n"); return -1; } - if (config->ulpi && init_ulpi_usb_controller(config, usbctlr)) { + if (config->ulpi && init_ulpi_usb_controller(config)) { printf("tegrausb: Cannot init port\n"); return -1; } @@ -558,7 +558,7 @@ int board_usb_init(const void *blob) return -1; } - if (add_port(&config, usb_pll[freq])) + if (add_port(&config)) return -1; set_host_mode(&config); } -- cgit From a4bdcc38c94f5d693b3ad65a70fd1aeac9436d64 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:26 +0000 Subject: tegra: usb: remove unneeded function parameter Just a dead parameter, never actually used. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/usb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index 07c1adefe3..2007483c9b 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -486,8 +486,7 @@ int tegrausb_stop_port(int portnum) return 0; } -int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, - struct fdt_usb *config) +int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) { const char *phy, *mode; @@ -535,7 +534,6 @@ int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_mhz, int board_usb_init(const void *blob) { struct fdt_usb config; - unsigned osc_freq = clock_get_rate(CLOCK_ID_OSC); enum clock_osc_freq freq; int node_list[USB_PORTS_MAX]; int node, count, i; @@ -552,7 +550,7 @@ int board_usb_init(const void *blob) node = node_list[i]; if (!node) continue; - if (fdt_decode_usb(blob, node, osc_freq, &config)) { + if (fdt_decode_usb(blob, node, &config)) { debug("Cannot decode USB node %s\n", fdt_get_name(blob, node, NULL)); return -1; -- cgit From fdb4b9a71c93d5bd9e04df52be4587516ade6fb1 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:27 +0000 Subject: tegra: usb: move controller init into start_port There is no need to init a USB controller before the upper layers indicate that they are actually going to use it. board_usb_init now only parses the device tree and sets up the common pll. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/usb.c | 57 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index 2007483c9b..e4165e04a5 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -79,6 +79,7 @@ struct fdt_usb { unsigned ulpi:1; /* 1 if port has external ULPI transceiver */ unsigned enabled:1; /* 1 to enable, 0 to disable */ unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */ + unsigned initialized:1; /* has this port already been initialized? */ enum dr_mode dr_mode; /* dual role mode */ enum periph_id periph_id;/* peripheral id */ struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */ @@ -426,44 +427,36 @@ static void config_clock(const u32 timing[]) timing[PARAM_CPCON], timing[PARAM_LFCON]); } -/** - * Add a new USB port to the list of available ports. - * - * @param config USB port configuration - * @return 0 if ok, -1 if error (too many ports) - */ -static int add_port(struct fdt_usb *config) +int tegrausb_start_port(int portnum, u32 *hccr, u32 *hcor) { - if (port_count == USB_PORTS_MAX) { - printf("tegrausb: Cannot register more than %d ports\n", - USB_PORTS_MAX); + struct fdt_usb *config; + struct usb_ctlr *usbctlr; + + if (portnum >= port_count) return -1; - } + + config = &port[portnum]; + + /* skip init, if the port is already initialized */ + if (config->initialized) + goto success; if (config->utmi && init_utmi_usb_controller(config)) { - printf("tegrausb: Cannot init port\n"); + printf("tegrausb: Cannot init port %d\n", portnum); return -1; } if (config->ulpi && init_ulpi_usb_controller(config)) { - printf("tegrausb: Cannot init port\n"); + printf("tegrausb: Cannot init port %d\n", portnum); return -1; } - port[port_count++] = *config; - - return 0; -} - -int tegrausb_start_port(int portnum, u32 *hccr, u32 *hcor) -{ - struct usb_ctlr *usbctlr; + set_host_mode(config); - if (portnum >= port_count) - return -1; - set_host_mode(&port[portnum]); + config->initialized = 1; - usbctlr = port[portnum].reg; +success: + usbctlr = config->reg; *hccr = (u32)&usbctlr->cap_length; *hcor = (u32)&usbctlr->usb_cmd; return 0; @@ -483,6 +476,8 @@ int tegrausb_stop_port(int portnum) writel(2, &usbctlr->usb_cmd); udelay(1000); + port[portnum].initialized = 0; + return 0; } @@ -546,6 +541,12 @@ int board_usb_init(const void *blob) count = fdtdec_find_aliases_for_id(blob, "usb", COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX); for (i = 0; i < count; i++) { + if (port_count == USB_PORTS_MAX) { + printf("tegrausb: Cannot register more than %d ports\n", + USB_PORTS_MAX); + return -1; + } + debug("USB %d: ", i); node = node_list[i]; if (!node) @@ -555,10 +556,10 @@ int board_usb_init(const void *blob) fdt_get_name(blob, node, NULL)); return -1; } + config.initialized = 0; - if (add_port(&config)) - return -1; - set_host_mode(&config); + /* add new USB port to the list of available ports */ + port[port_count++] = config; } return 0; -- cgit From a63eb6bbcc73c6bde716b23383139b8079f02144 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:28 +0000 Subject: tegra: usb: various small cleanups Remove unneeded headers, function prototype and stale comment, that doesn't match the actual codebase anymore. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/usb.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c index e4165e04a5..3fdd5df066 100644 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ b/arch/arm/cpu/armv7/tegra20/usb.c @@ -25,21 +25,15 @@ #include #include #include -#include -#include -#include #include #include -#include -#include -#include #include #include #ifdef CONFIG_USB_ULPI #ifndef CONFIG_USB_ULPI_VIEWPORT #error "To use CONFIG_USB_ULPI on Tegra Boards you have to also \ - define CONFIG_USB_ULPI_VIEWPORT" + define CONFIG_USB_ULPI_VIEWPORT" #endif #endif @@ -191,11 +185,6 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) /* Enable the UTMIP PHY */ if (config->utmi) setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB); - - /* - * TODO: where do we take the USB1 out of reset? The old code would - * take USB3 out of reset, but not USB1. This code doesn't do either. - */ } /* set up the UTMI USB controller with the parameters provided */ -- cgit From 7ae18f3725fe3e2033888cf431f71ac08aaa8e1c Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 7 Feb 2013 07:16:29 +0000 Subject: tegra: usb: move implementation into right directory This moves the Tegra USB implementation into the drivers/usb/host directory. Note that this merges the old /arch/arm/cpu/armv7/tegra20/usb.c file into ehci-tegra.c. No code changes, just moving stuff around. v2: While at it also move some defines and the usb.h header file to make usb driver usable for Tegra30. NOTE: A lot more work is required to properly init the PHYs and PLL_U on Tegra30, this is just to make porting easier and it does no harm here. Signed-off-by: Lucas Stach Acked-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/cpu/armv7/tegra20/Makefile | 1 - arch/arm/cpu/armv7/tegra20/usb.c | 555 ------------------------------------ 2 files changed, 556 deletions(-) delete mode 100644 arch/arm/cpu/armv7/tegra20/usb.c (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/armv7/tegra20/Makefile b/arch/arm/cpu/armv7/tegra20/Makefile index 54ed8c48b4..c8a8504e16 100644 --- a/arch/arm/cpu/armv7/tegra20/Makefile +++ b/arch/arm/cpu/armv7/tegra20/Makefile @@ -27,7 +27,6 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o -COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o COBJS-$(CONFIG_PWM_TEGRA) += pwm.o COBJS-$(CONFIG_VIDEO_TEGRA) += display.o diff --git a/arch/arm/cpu/armv7/tegra20/usb.c b/arch/arm/cpu/armv7/tegra20/usb.c deleted file mode 100644 index 3fdd5df066..0000000000 --- a/arch/arm/cpu/armv7/tegra20/usb.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * (C) Copyright 2010,2011 NVIDIA Corporation - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_USB_ULPI - #ifndef CONFIG_USB_ULPI_VIEWPORT - #error "To use CONFIG_USB_ULPI on Tegra Boards you have to also \ - define CONFIG_USB_ULPI_VIEWPORT" - #endif -#endif - -enum { - USB_PORTS_MAX = 3, /* Maximum ports we allow */ -}; - -/* Parameters we need for USB */ -enum { - PARAM_DIVN, /* PLL FEEDBACK DIVIDer */ - PARAM_DIVM, /* PLL INPUT DIVIDER */ - PARAM_DIVP, /* POST DIVIDER (2^N) */ - PARAM_CPCON, /* BASE PLLC CHARGE Pump setup ctrl */ - PARAM_LFCON, /* BASE PLLC LOOP FILter setup ctrl */ - PARAM_ENABLE_DELAY_COUNT, /* PLL-U Enable Delay Count */ - PARAM_STABLE_COUNT, /* PLL-U STABLE count */ - PARAM_ACTIVE_DELAY_COUNT, /* PLL-U Active delay count */ - PARAM_XTAL_FREQ_COUNT, /* PLL-U XTAL frequency count */ - PARAM_DEBOUNCE_A_TIME, /* 10MS DELAY for BIAS_DEBOUNCE_A */ - PARAM_BIAS_TIME, /* 20US DELAY AFter bias cell op */ - - PARAM_COUNT -}; - -/* Possible port types (dual role mode) */ -enum dr_mode { - DR_MODE_NONE = 0, - DR_MODE_HOST, /* supports host operation */ - DR_MODE_DEVICE, /* supports device operation */ - DR_MODE_OTG, /* supports both */ -}; - -/* Information about a USB port */ -struct fdt_usb { - struct usb_ctlr *reg; /* address of registers in physical memory */ - unsigned utmi:1; /* 1 if port has external tranceiver, else 0 */ - unsigned ulpi:1; /* 1 if port has external ULPI transceiver */ - unsigned enabled:1; /* 1 to enable, 0 to disable */ - unsigned has_legacy_mode:1; /* 1 if this port has legacy mode */ - unsigned initialized:1; /* has this port already been initialized? */ - enum dr_mode dr_mode; /* dual role mode */ - enum periph_id periph_id;/* peripheral id */ - struct fdt_gpio_state vbus_gpio; /* GPIO for vbus enable */ - struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */ -}; - -static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */ -static unsigned port_count; /* Number of available ports */ - -/* - * This table has USB timing parameters for each Oscillator frequency we - * support. There are four sets of values: - * - * 1. PLLU configuration information (reference clock is osc/clk_m and - * PLLU-FOs are fixed at 12MHz/60MHz/480MHz). - * - * Reference frequency 13.0MHz 19.2MHz 12.0MHz 26.0MHz - * ---------------------------------------------------------------------- - * DIVN 960 (0x3c0) 200 (0c8) 960 (3c0h) 960 (3c0) - * DIVM 13 (0d) 4 (04) 12 (0c) 26 (1a) - * Filter frequency (MHz) 1 4.8 6 2 - * CPCON 1100b 0011b 1100b 1100b - * LFCON0 0 0 0 0 - * - * 2. PLL CONFIGURATION & PARAMETERS for different clock generators: - * - * Reference frequency 13.0MHz 19.2MHz 12.0MHz 26.0MHz - * --------------------------------------------------------------------------- - * PLLU_ENABLE_DLY_COUNT 02 (0x02) 03 (03) 02 (02) 04 (04) - * PLLU_STABLE_COUNT 51 (33) 75 (4B) 47 (2F) 102 (66) - * PLL_ACTIVE_DLY_COUNT 05 (05) 06 (06) 04 (04) 09 (09) - * XTAL_FREQ_COUNT 127 (7F) 187 (BB) 118 (76) 254 (FE) - * - * 3. Debounce values IdDig, Avalid, Bvalid, VbusValid, VbusWakeUp, and - * SessEnd. Each of these signals have their own debouncer and for each of - * those one out of two debouncing times can be chosen (BIAS_DEBOUNCE_A or - * BIAS_DEBOUNCE_B). - * - * The values of DEBOUNCE_A and DEBOUNCE_B are calculated as follows: - * 0xffff -> No debouncing at all - * ms = *1000 / (1/19.2MHz) / 4 - * - * So to program a 1 ms debounce for BIAS_DEBOUNCE_A, we have: - * BIAS_DEBOUNCE_A[15:0] = 1000 * 19.2 / 4 = 4800 = 0x12c0 - * - * We need to use only DebounceA for BOOTROM. We don't need the DebounceB - * values, so we can keep those to default. - * - * 4. The 20 microsecond delay after bias cell operation. - */ -static const unsigned usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { - /* DivN, DivM, DivP, CPCON, LFCON, Delays Debounce, Bias */ - { 0x3C0, 0x0D, 0x00, 0xC, 0, 0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 }, - { 0x0C8, 0x04, 0x00, 0x3, 0, 0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 }, - { 0x3C0, 0x0C, 0x00, 0xC, 0, 0x02, 0x2F, 0x04, 0x76, 0x7530, 5 }, - { 0x3C0, 0x1A, 0x00, 0xC, 0, 0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 } -}; - -/* UTMIP Idle Wait Delay */ -static const u8 utmip_idle_wait_delay = 17; - -/* UTMIP Elastic limit */ -static const u8 utmip_elastic_limit = 16; - -/* UTMIP High Speed Sync Start Delay */ -static const u8 utmip_hs_sync_start_delay = 9; - -/* Put the port into host mode */ -static void set_host_mode(struct fdt_usb *config) -{ - /* - * If we are an OTG port, check if remote host is driving VBus and - * bail out in this case. - */ - if (config->dr_mode == DR_MODE_OTG && - (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS)) - return; - - /* - * If not driving, we set the GPIO to enable VBUS. We assume - * that the pinmux is set up correctly for this. - */ - if (fdt_gpio_isvalid(&config->vbus_gpio)) { - fdtdec_setup_gpio(&config->vbus_gpio); - gpio_direction_output(config->vbus_gpio.gpio, - (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ? - 0 : 1); - debug("set_host_mode: GPIO %d %s\n", config->vbus_gpio.gpio, - (config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW) ? - "low" : "high"); - } -} - -void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) -{ - /* Reset the USB controller with 2us delay */ - reset_periph(config->periph_id, 2); - - /* - * Set USB1_NO_LEGACY_MODE to 1, Registers are accessible under - * base address - */ - if (config->has_legacy_mode) - setbits_le32(&usbctlr->usb1_legacy_ctrl, USB1_NO_LEGACY_MODE); - - /* Put UTMIP1/3 in reset */ - setbits_le32(&usbctlr->susp_ctrl, UTMIP_RESET); - - /* Enable the UTMIP PHY */ - if (config->utmi) - setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB); -} - -/* set up the UTMI USB controller with the parameters provided */ -static int init_utmi_usb_controller(struct fdt_usb *config) -{ - u32 val; - int loop_count; - const unsigned *timing; - struct usb_ctlr *usbctlr = config->reg; - - clock_enable(config->periph_id); - - /* Reset the usb controller */ - usbf_reset_controller(config, usbctlr); - - /* Stop crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN low */ - clrbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN); - - /* Follow the crystal clock disable by >100ns delay */ - udelay(1); - - /* - * To Use the A Session Valid for cable detection logic, VBUS_WAKEUP - * mux must be switched to actually use a_sess_vld threshold. - */ - if (fdt_gpio_isvalid(&config->vbus_gpio)) { - clrsetbits_le32(&usbctlr->usb1_legacy_ctrl, - VBUS_SENSE_CTL_MASK, - VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT); - } - - /* - * PLL Delay CONFIGURATION settings. The following parameters control - * the bring up of the plls. - */ - timing = usb_pll[clock_get_osc_freq()]; - - val = readl(&usbctlr->utmip_misc_cfg1); - clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK, - timing[PARAM_STABLE_COUNT] << UTMIP_PLLU_STABLE_COUNT_SHIFT); - clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK, - timing[PARAM_ACTIVE_DELAY_COUNT] << - UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT); - writel(val, &usbctlr->utmip_misc_cfg1); - - /* Set PLL enable delay count and crystal frequency count */ - val = readl(&usbctlr->utmip_pll_cfg1); - clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK, - timing[PARAM_ENABLE_DELAY_COUNT] << - UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT); - clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK, - timing[PARAM_XTAL_FREQ_COUNT] << - UTMIP_XTAL_FREQ_COUNT_SHIFT); - writel(val, &usbctlr->utmip_pll_cfg1); - - /* Setting the tracking length time */ - clrsetbits_le32(&usbctlr->utmip_bias_cfg1, - UTMIP_BIAS_PDTRK_COUNT_MASK, - timing[PARAM_BIAS_TIME] << UTMIP_BIAS_PDTRK_COUNT_SHIFT); - - /* Program debounce time for VBUS to become valid */ - clrsetbits_le32(&usbctlr->utmip_debounce_cfg0, - UTMIP_DEBOUNCE_CFG0_MASK, - timing[PARAM_DEBOUNCE_A_TIME] << UTMIP_DEBOUNCE_CFG0_SHIFT); - - setbits_le32(&usbctlr->utmip_tx_cfg0, UTMIP_FS_PREAMBLE_J); - - /* Disable battery charge enabling bit */ - setbits_le32(&usbctlr->utmip_bat_chrg_cfg0, UTMIP_PD_CHRG); - - clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_XCVR_LSBIAS_SE); - setbits_le32(&usbctlr->utmip_spare_cfg0, FUSE_SETUP_SEL); - - /* - * Configure the UTMIP_IDLE_WAIT and UTMIP_ELASTIC_LIMIT - * Setting these fields, together with default values of the - * other fields, results in programming the registers below as - * follows: - * UTMIP_HSRX_CFG0 = 0x9168c000 - * UTMIP_HSRX_CFG1 = 0x13 - */ - - /* Set PLL enable delay count and Crystal frequency count */ - val = readl(&usbctlr->utmip_hsrx_cfg0); - clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK, - utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT); - clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK, - utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT); - writel(val, &usbctlr->utmip_hsrx_cfg0); - - /* Configure the UTMIP_HS_SYNC_START_DLY */ - clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1, - UTMIP_HS_SYNC_START_DLY_MASK, - utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT); - - /* Preceed the crystal clock disable by >100ns delay. */ - udelay(1); - - /* Resuscitate crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN */ - setbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN); - - /* Finished the per-controller init. */ - - /* De-assert UTMIP_RESET to bring out of reset. */ - clrbits_le32(&usbctlr->susp_ctrl, UTMIP_RESET); - - /* Wait for the phy clock to become valid in 100 ms */ - for (loop_count = 100000; loop_count != 0; loop_count--) { - if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID) - break; - udelay(1); - } - if (!loop_count) - return -1; - - /* Disable ICUSB FS/LS transceiver */ - clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1); - - /* Select UTMI parallel interface */ - clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, - PTS_UTMI << PTS_SHIFT); - clrbits_le32(&usbctlr->port_sc1, STS); - - /* Deassert power down state */ - clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN | - UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN); - clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN | - UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN); - - return 0; -} - -#ifdef CONFIG_USB_ULPI -/* if board file does not set a ULPI reference frequency we default to 24MHz */ -#ifndef CONFIG_ULPI_REF_CLK -#define CONFIG_ULPI_REF_CLK 24000000 -#endif - -/* set up the ULPI USB controller with the parameters provided */ -static int init_ulpi_usb_controller(struct fdt_usb *config) -{ - u32 val; - int loop_count; - struct ulpi_viewport ulpi_vp; - struct usb_ctlr *usbctlr = config->reg; - - /* set up ULPI reference clock on pllp_out4 */ - clock_enable(PERIPH_ID_DEV2_OUT); - clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK); - - /* reset ULPI phy */ - if (fdt_gpio_isvalid(&config->phy_reset_gpio)) { - fdtdec_setup_gpio(&config->phy_reset_gpio); - gpio_direction_output(config->phy_reset_gpio.gpio, 0); - mdelay(5); - gpio_set_value(config->phy_reset_gpio.gpio, 1); - } - - /* Reset the usb controller */ - clock_enable(config->periph_id); - usbf_reset_controller(config, usbctlr); - - /* enable pinmux bypass */ - setbits_le32(&usbctlr->ulpi_timing_ctrl_0, - ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP); - - /* Select ULPI parallel interface */ - clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, PTS_ULPI << PTS_SHIFT); - - /* enable ULPI transceiver */ - setbits_le32(&usbctlr->susp_ctrl, ULPI_PHY_ENB); - - /* configure ULPI transceiver timings */ - val = 0; - writel(val, &usbctlr->ulpi_timing_ctrl_1); - - val |= ULPI_DATA_TRIMMER_SEL(4); - val |= ULPI_STPDIRNXT_TRIMMER_SEL(4); - val |= ULPI_DIR_TRIMMER_SEL(4); - writel(val, &usbctlr->ulpi_timing_ctrl_1); - udelay(10); - - val |= ULPI_DATA_TRIMMER_LOAD; - val |= ULPI_STPDIRNXT_TRIMMER_LOAD; - val |= ULPI_DIR_TRIMMER_LOAD; - writel(val, &usbctlr->ulpi_timing_ctrl_1); - - /* set up phy for host operation with external vbus supply */ - ulpi_vp.port_num = 0; - ulpi_vp.viewport_addr = (u32)&usbctlr->ulpi_viewport; - - if (ulpi_init(&ulpi_vp)) { - printf("Tegra ULPI viewport init failed\n"); - return -1; - } - - ulpi_set_vbus(&ulpi_vp, 1, 1); - ulpi_set_vbus_indicator(&ulpi_vp, 1, 1, 0); - - /* enable wakeup events */ - setbits_le32(&usbctlr->port_sc1, WKCN | WKDS | WKOC); - - /* Enable and wait for the phy clock to become valid in 100 ms */ - setbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); - for (loop_count = 100000; loop_count != 0; loop_count--) { - if (readl(&usbctlr->susp_ctrl) & USB_PHY_CLK_VALID) - break; - udelay(1); - } - if (!loop_count) - return -1; - clrbits_le32(&usbctlr->susp_ctrl, USB_SUSP_CLR); - - return 0; -} -#else -static int init_ulpi_usb_controller(struct fdt_usb *config) -{ - printf("No code to set up ULPI controller, please enable" - "CONFIG_USB_ULPI and CONFIG_USB_ULPI_VIEWPORT"); - return -1; -} -#endif - -static void config_clock(const u32 timing[]) -{ - clock_start_pll(CLOCK_ID_USB, - timing[PARAM_DIVM], timing[PARAM_DIVN], timing[PARAM_DIVP], - timing[PARAM_CPCON], timing[PARAM_LFCON]); -} - -int tegrausb_start_port(int portnum, u32 *hccr, u32 *hcor) -{ - struct fdt_usb *config; - struct usb_ctlr *usbctlr; - - if (portnum >= port_count) - return -1; - - config = &port[portnum]; - - /* skip init, if the port is already initialized */ - if (config->initialized) - goto success; - - if (config->utmi && init_utmi_usb_controller(config)) { - printf("tegrausb: Cannot init port %d\n", portnum); - return -1; - } - - if (config->ulpi && init_ulpi_usb_controller(config)) { - printf("tegrausb: Cannot init port %d\n", portnum); - return -1; - } - - set_host_mode(config); - - config->initialized = 1; - -success: - usbctlr = config->reg; - *hccr = (u32)&usbctlr->cap_length; - *hcor = (u32)&usbctlr->usb_cmd; - return 0; -} - -int tegrausb_stop_port(int portnum) -{ - struct usb_ctlr *usbctlr; - - usbctlr = port[portnum].reg; - - /* Stop controller */ - writel(0, &usbctlr->usb_cmd); - udelay(1000); - - /* Initiate controller reset */ - writel(2, &usbctlr->usb_cmd); - udelay(1000); - - port[portnum].initialized = 0; - - return 0; -} - -int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) -{ - const char *phy, *mode; - - config->reg = (struct usb_ctlr *)fdtdec_get_addr(blob, node, "reg"); - mode = fdt_getprop(blob, node, "dr_mode", NULL); - if (mode) { - if (0 == strcmp(mode, "host")) - config->dr_mode = DR_MODE_HOST; - else if (0 == strcmp(mode, "peripheral")) - config->dr_mode = DR_MODE_DEVICE; - else if (0 == strcmp(mode, "otg")) - config->dr_mode = DR_MODE_OTG; - else { - debug("%s: Cannot decode dr_mode '%s'\n", __func__, - mode); - return -FDT_ERR_NOTFOUND; - } - } else { - config->dr_mode = DR_MODE_HOST; - } - - phy = fdt_getprop(blob, node, "phy_type", NULL); - config->utmi = phy && 0 == strcmp("utmi", phy); - config->ulpi = phy && 0 == strcmp("ulpi", phy); - config->enabled = fdtdec_get_is_enabled(blob, node); - config->has_legacy_mode = fdtdec_get_bool(blob, node, - "nvidia,has-legacy-mode"); - config->periph_id = clock_decode_periph_id(blob, node); - if (config->periph_id == PERIPH_ID_NONE) { - debug("%s: Missing/invalid peripheral ID\n", __func__); - return -FDT_ERR_NOTFOUND; - } - fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio); - fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio", - &config->phy_reset_gpio); - debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, " - "vbus=%d, phy_reset=%d, dr_mode=%d\n", - config->enabled, config->has_legacy_mode, config->utmi, - config->ulpi, config->periph_id, config->vbus_gpio.gpio, - config->phy_reset_gpio.gpio, config->dr_mode); - - return 0; -} - -int board_usb_init(const void *blob) -{ - struct fdt_usb config; - enum clock_osc_freq freq; - int node_list[USB_PORTS_MAX]; - int node, count, i; - - /* Set up the USB clocks correctly based on our oscillator frequency */ - freq = clock_get_osc_freq(); - config_clock(usb_pll[freq]); - - /* count may return <0 on error */ - count = fdtdec_find_aliases_for_id(blob, "usb", - COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX); - for (i = 0; i < count; i++) { - if (port_count == USB_PORTS_MAX) { - printf("tegrausb: Cannot register more than %d ports\n", - USB_PORTS_MAX); - return -1; - } - - debug("USB %d: ", i); - node = node_list[i]; - if (!node) - continue; - if (fdt_decode_usb(blob, node, &config)) { - debug("Cannot decode USB node %s\n", - fdt_get_name(blob, node, NULL)); - return -1; - } - config.initialized = 0; - - /* add new USB port to the list of available ports */ - port[port_count++] = config; - } - - return 0; -} -- cgit From 702b87289438cfc3165408f0eaf999b0b67c1e7e Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Wed, 27 Feb 2013 11:10:01 +0000 Subject: Tegra114: I2C: Take DVFS out of reset to allow I2C5 (PWR_I2C) to work I2C driver can now probe dev 0 (PWR_I2C, where the PMU, etc. lives). This is needed so that the SDIO slot power can be brought up for the MMC driver, so it has to precede those commits. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/cpu/arm720t/tegra114/cpu.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c index 5962e15b4f..0b2157a0df 100644 --- a/arch/arm/cpu/arm720t/tegra114/cpu.c +++ b/arch/arm/cpu/arm720t/tegra114/cpu.c @@ -201,6 +201,7 @@ void t114_init_clocks(void) reset_set_enable(PERIPH_ID_MSELECT, 0); reset_set_enable(PERIPH_ID_EMC1, 0); reset_set_enable(PERIPH_ID_MC1, 0); + reset_set_enable(PERIPH_ID_DVFS, 0); debug("t114_init_clocks exit\n"); } -- cgit From 16bb08d19a5ecb9c3e90ab2394d7c5c40955ee60 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 28 Feb 2013 12:40:09 +0000 Subject: ARM: tegra: implement WAR for Tegra114 CPU reset vector A Tegra114 HW bug prevents the main CPU vector from being modified under certain circumstances. Tegra114 A01P and later with a patched boot ROM set the CPU reset vector to 0x4003fffc (end of IRAM). This allows placing an arbitrary jump instruction at that location, in order to redirect to the desired reset vector location. Modify Tegra114's start_cpu() to make use of this feature. This allows CPUs with the patched boot ROM to boot. Based-on-work-by: Jimmy Zhang . Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/cpu/arm720t/tegra114/cpu.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/arm720t/tegra114/cpu.c b/arch/arm/cpu/arm720t/tegra114/cpu.c index 0b2157a0df..6a94179d4a 100644 --- a/arch/arm/cpu/arm720t/tegra114/cpu.c +++ b/arch/arm/cpu/arm720t/tegra114/cpu.c @@ -270,6 +270,8 @@ void powerup_cpus(void) void start_cpu(u32 reset_vector) { + u32 imme, inst; + debug("start_cpu entry, reset_vector = %x\n", reset_vector); t114_init_clocks(); @@ -286,12 +288,38 @@ void start_cpu(u32 reset_vector) /* Take CPU(s) out of reset */ remove_cpu_resets(); + /* Set the entry point for CPU execution from reset */ + /* - * Set the entry point for CPU execution from reset, - * if it's a non-zero value. + * A01P with patched boot ROM; vector hard-coded to 0x4003fffc. + * See nvbug 1193357 for details. */ - if (reset_vector) - writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); + + /* mov r0, #lsb(reset_vector) */ + imme = reset_vector & 0xffff; + inst = imme & 0xfff; + inst |= ((imme >> 12) << 16); + inst |= 0xe3000000; + writel(inst, 0x4003fff0); + + /* movt r0, #msb(reset_vector) */ + imme = (reset_vector >> 16) & 0xffff; + inst = imme & 0xfff; + inst |= ((imme >> 12) << 16); + inst |= 0xe3400000; + writel(inst, 0x4003fff4); + + /* bx r0 */ + writel(0xe12fff10, 0x4003fff8); + + /* b -12 */ + imme = (u32)-20; + inst = (imme >> 2) & 0xffffff; + inst |= 0xea000000; + writel(inst, 0x4003fffc); + + /* Write to orignal location for compatibility */ + writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); /* If the CPU(s) don't already have power, power 'em up */ powerup_cpus(); -- cgit From 8b7776b9f95d542d0e81357c4f8aa32f7bf466e5 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Fri, 1 Mar 2013 14:38:20 -0700 Subject: Tegra114: pinmux: Update pinmux tables & code, fix a bug w/SDMMC3 init Use the latest tables & code from our internal U-Boot repo. The SDMMC3_CD, CLK_LB_IN and CLK_LB_OUT offsets in the pingroup table were off by a few indices, causing the pinmux init code to write bad data to the PINMUX_AUX_ regs. This also enabled the lock bit, which made it impossible to reconfig the pads correctly for SDMMC3 (SD card on Dalmore) operation. Also fixes SPI_CS2_N, USB_VBUS_EN0, HDMI_CEC and UART2_RXD/TXD muxes. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/cpu/tegra114-common/pinmux.c | 214 ++++++++++++++++++++-------------- 1 file changed, 127 insertions(+), 87 deletions(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/tegra114-common/pinmux.c b/arch/arm/cpu/tegra114-common/pinmux.c index 52b3ec47aa..27b5f694fa 100644 --- a/arch/arm/cpu/tegra114-common/pinmux.c +++ b/arch/arm/cpu/tegra114-common/pinmux.c @@ -37,6 +37,7 @@ struct tegra_pingroup_desc { #define PMUX_OD_SHIFT 6 #define PMUX_LOCK_SHIFT 7 #define PMUX_IO_RESET_SHIFT 8 +#define PMUX_RCV_SEL_SHIFT 9 /* Convenient macro for defining pin group properties */ #define PIN(pg_name, vdd, f0, f1, f2, f3, iod) \ @@ -58,6 +59,10 @@ struct tegra_pingroup_desc { #define PINO(pg_name, vdd, f0, f1, f2, f3) \ PIN(pg_name, vdd, f0, f1, f2, f3, OUTPUT) +/* A pin group number which is not used */ +#define PIN_RESERVED \ + PIN(NONE, NONE, INVALID, INVALID, INVALID, INVALID, NONE) + const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { /* NAME VDD f0 f1 f2 f3 */ PINI(ULPI_DATA0, BB, SPI3, HSI, UARTA, ULPI), @@ -84,71 +89,71 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { PINI(SDMMC1_DAT2, SDMMC1, SDMMC1, PWM0, SPI4, UARTA), PINI(SDMMC1_DAT1, SDMMC1, SDMMC1, PWM1, SPI4, UARTA), PINI(SDMMC1_DAT0, SDMMC1, SDMMC1, RSVD2, SPI4, UARTA), - PINI(GPIO_PV2, BB, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(GPIO_PV3, BB, RSVD1, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x3060 - 0x3064 */ + PIN_RESERVED, PINI(CLK2_OUT, SDMMC1, EXTPERIPH2, RSVD2, RSVD3, RSVD4), PINI(CLK2_REQ, SDMMC1, DAP, RSVD2, RSVD3, RSVD4), - PINO(LCD_PWR1, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_PWR2, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_SDIN, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_SDOUT, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_WR_N, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_CS0_N, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_DC0, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_SCK, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_PWR0, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_PCLK, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_DE, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_HSYNC, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_VSYNC, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D0, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D1, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D2, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D3, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D4, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D5, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D6, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D7, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D8, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D9, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D10, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D11, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D12, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D13, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D14, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D15, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D16, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D17, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D18, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D19, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D20, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D21, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D22, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_D23, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_CS1_N, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_M1, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINO(LCD_DC1, LCD, RSVD1, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x3070 - 0x310c */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, PINI(HDMI_INT, LCD, RSVD1, RSVD2, RSVD3, RSVD4), PINI(DDC_SCL, LCD, I2C4, RSVD2, RSVD3, RSVD4), PINI(DDC_SDA, LCD, I2C4, RSVD2, RSVD3, RSVD4), - PINI(CRT_HSYNC, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(CRT_VSYNC, LCD, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D0, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D1, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D2, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D3, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D4, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D5, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D6, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D7, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D8, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D9, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D10, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_D11, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_PCLK, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_MCLK, VI, RSVD1, RSVD3, RSVD3, RSVD4), - PINI(VI_VSYNC, VI, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(VI_HSYNC, VI, RSVD1, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x311c - 0x3160 */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, PINI(UART2_RXD, UART, UARTB, SPDIF, UARTA, SPI4), PINI(UART2_TXD, UART, UARTB, SPDIF, UARTA, SPI4), PINI(UART2_RTS_N, UART, UARTA, UARTB, RSVD3, SPI4), @@ -220,7 +225,7 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { PINI(SDMMC4_DAT5, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), PINI(SDMMC4_DAT6, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), PINI(SDMMC4_DAT7, SDMMC4, SDMMC4, RSVD2, GMI, RSVD4), - PINI(SDMMC4_RST_N, SDMMC4, RSVD1, RSVD2, RSVD3, SDMMC4), + PIN_RESERVED, /* Reserved by t114: 0x3280 */ PINI(CAM_MCLK, CAM, VI, VI_ALT1, VI_ALT2, RSVD4), PINI(GPIO_PCC1, CAM, I2S4, RSVD2, RSVD3, RSVD4), PINI(GPIO_PBB0, CAM, I2S4, VI, VI_ALT1, VI_ALT3), @@ -246,11 +251,11 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { PINI(KB_ROW8, SYS, KBC, RSVD2, RSVD3, UARTA), PINI(KB_ROW9, SYS, KBC, RSVD2, RSVD3, UARTA), PINI(KB_ROW10, SYS, KBC, RSVD2, RSVD3, UARTA), - PINI(KB_ROW11, SYS, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(KB_ROW12, SYS, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(KB_ROW13, SYS, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(KB_ROW14, SYS, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(KB_ROW15, SYS, RSVD1, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x32e8 - 0x32f8 */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, PINI(KB_COL0, SYS, KBC, USB, SPI2, EMC_DLL), PINI(KB_COL1, SYS, KBC, RSVD2, SPI2, EMC_DLL), PINI(KB_COL2, SYS, KBC, RSVD2, SPI2, RSVD4), @@ -278,36 +283,46 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { PINI(DAP2_DIN, AUDIO, I2S1, HDA, RSVD3, RSVD4), PINI(DAP2_DOUT, AUDIO, I2S1, HDA, RSVD3, RSVD4), PINI(DAP2_SCLK, AUDIO, I2S1, HDA, RSVD3, RSVD4), - PINI(SPI2_MOSI, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), - PINI(SPI2_MISO, AUDIO, SPI6, RSVD2, RSVD3, RSVD4), - PINI(SPI2_CS0_N, AUDIO, SPI6, SPI1, RSVD3, RSVD4), - PINI(SPI2_SCK, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), - PINI(SPI1_MOSI, AUDIO, RSVD1, SPI1, SPI2, DAP2), - PINI(SPI1_SCK, AUDIO, RSVD1, SPI1, SPI2, RSVD4), - PINI(SPI1_CS0_N, AUDIO, SPI6, SPI1, SPI2, RSVD4), - PINI(SPI1_MISO, AUDIO, RSVD1, SPI1, SPI2, RSVD4), - PINI(SPI2_CS1_N, AUDIO, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(SPI2_CS2_N, AUDIO, RSVD1, RSVD2, RSVD3, RSVD4), + PINI(DVFS_PWM, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), + PINI(GPIO_X1_AUD, AUDIO, SPI6, RSVD2, RSVD3, RSVD4), + PINI(GPIO_X3_AUD, AUDIO, SPI6, SPI1, RSVD3, RSVD4), + PINI(DVFS_CLK, AUDIO, SPI6, CLDVFS, RSVD3, RSVD4), + PINI(GPIO_X4_AUD, AUDIO, RSVD1, SPI1, SPI2, DAP2), + PINI(GPIO_X5_AUD, AUDIO, RSVD1, SPI1, SPI2, RSVD4), + PINI(GPIO_X6_AUD, AUDIO, SPI6, SPI1, SPI2, RSVD4), + PINI(GPIO_X7_AUD, AUDIO, RSVD1, SPI1, SPI2, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x3388 - 0x338c */ + PIN_RESERVED, PINI(SDMMC3_CLK, SDMMC3, SDMMC3, RSVD2, RSVD3, SPI3), PINI(SDMMC3_CMD, SDMMC3, SDMMC3, PWM3, UARTA, SPI3), PINI(SDMMC3_DAT0, SDMMC3, SDMMC3, RSVD2, RSVD3, SPI3), PINI(SDMMC3_DAT1, SDMMC3, SDMMC3, PWM2, UARTA, SPI3), PINI(SDMMC3_DAT2, SDMMC3, SDMMC3, PWM1, DISPA, SPI3), PINI(SDMMC3_DAT3, SDMMC3, SDMMC3, PWM0, DISPB, SPI3), - PINI(SDMMC3_DAT4, SDMMC3, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(SDMMC3_DAT5, SDMMC3, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(SDMMC3_DAT6, SDMMC3, RSVD1, RSVD2, RSVD3, RSVD4), - PINI(SDMMC3_DAT7, SDMMC3, RSVD1, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x33a8 - 0x33dc */ + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, + PIN_RESERVED, PINI(HDMI_CEC, SYS, CEC, SDMMC3, RSVD3, SOC), PINI(SDMMC1_WP_N, SDMMC1, SDMMC1, CLK12, SPI4, UARTA), - PINI(SDMMC3_CD_N, SDMMC3, SDMMC3, OWR, RSVD3, RSVD4), - PINI(SPI1_CS1_N, AUDIO, SPI6, RSVD2, SPI2, I2C1), - PINI(SPI1_CS2_N, AUDIO, SPI6, SPI1, SPI2, I2C1), - PINI(USB_VBUS_EN0, SYS, USB, RSVD2, RSVD3, RSVD4), - PINI(USB_VBUS_EN1, SYS, USB, RSVD2, RSVD3, RSVD4), + PINI(SDMMC3_CD_N, SYS, SDMMC3, OWR, RSVD3, RSVD4), + PINI(GPIO_W2_AUD, AUDIO, SPI6, RSVD2, SPI2, I2C1), + PINI(GPIO_W3_AUD, AUDIO, SPI6, SPI1, SPI2, I2C1), + PINI(USB_VBUS_EN0, LCD, USB, RSVD2, RSVD3, RSVD4), + PINI(USB_VBUS_EN1, LCD, USB, RSVD2, RSVD3, RSVD4), PINI(SDMMC3_CLK_LB_IN, SDMMC3, SDMMC3, RSVD2, RSVD3, RSVD4), - PINO(SDMMC3_CLK_LB_OUT, SDMMC3, SDMMC3, RSVD2, RSVD3, RSVD4), - PINO(NAND_GMI_CLK_LB, GMI, SDMMC2, NAND, GMI, RSVD4), + PINI(SDMMC3_CLK_LB_OUT, SDMMC3, SDMMC3, RSVD2, RSVD3, RSVD4), + PIN_RESERVED, /* Reserved by t114: 0x3404 */ PINO(RESET_OUT_N, SYS, RSVD1, RSVD2, RSVD3, RESET_OUT_N), }; @@ -484,6 +499,30 @@ static int pinmux_set_ioreset(enum pmux_pingrp pin, return 0; } +static int pinmux_set_rcv_sel(enum pmux_pingrp pin, + enum pmux_pin_rcv_sel rcv_sel) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pin_rcv_sel = &pmt->pmt_ctl[pin]; + u32 reg; + + /* Error check on pin and rcv_sel */ + assert(pmux_pingrp_isvalid(pin)); + assert(pmux_pin_rcv_sel_isvalid(rcv_sel)); + + if (rcv_sel == PMUX_PIN_RCV_SEL_DEFAULT) + return 0; + + reg = readl(pin_rcv_sel); + reg &= ~(0x1 << PMUX_RCV_SEL_SHIFT); + if (rcv_sel == PMUX_PIN_RCV_SEL_HIGH) + reg |= (0x1 << PMUX_RCV_SEL_SHIFT); + writel(reg, pin_rcv_sel); + + return 0; +} + void pinmux_config_pingroup(struct pingroup_config *config) { enum pmux_pingrp pin = config->pingroup; @@ -495,6 +534,7 @@ void pinmux_config_pingroup(struct pingroup_config *config) pinmux_set_lock(pin, config->lock); pinmux_set_od(pin, config->od); pinmux_set_ioreset(pin, config->ioreset); + pinmux_set_rcv_sel(pin, config->rcv_sel); } void pinmux_config_table(struct pingroup_config *config, int len) -- cgit From 8ca79b2ff467bda3bc1cfe7fe566f0c1189881dc Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Wed, 6 Mar 2013 16:16:22 -0700 Subject: Tegra30: Cardhu: Add pad config tables/code based on pinmux code Pad config registers exist in APB_MISC_GP space, and control slew rate, drive strengh, schmidt, high-speed, and low-power modes for all of the pingroups in Tegra30. This builds off of the pinmux way of constructing init tables to configure select pads (SDIOCFG, for instance) during pinmux_init(). Currently, only SDIO1CFG is changed as per the TRM to work with the SD-card slot on Cardhu. Thanks to StephenW for the suggestion/original idea. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/cpu/tegra30-common/pinmux.c | 190 ++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 1 deletion(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/tegra30-common/pinmux.c b/arch/arm/cpu/tegra30-common/pinmux.c index 122665fd3c..eecf0580bc 100644 --- a/arch/arm/cpu/tegra30-common/pinmux.c +++ b/arch/arm/cpu/tegra30-common/pinmux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -38,6 +38,19 @@ struct tegra_pingroup_desc { #define PMUX_LOCK_SHIFT 7 #define PMUX_IO_RESET_SHIFT 8 +#define PGRP_HSM_SHIFT 2 +#define PGRP_SCHMT_SHIFT 3 +#define PGRP_LPMD_SHIFT 4 +#define PGRP_LPMD_MASK (3 << PGRP_LPMD_SHIFT) +#define PGRP_DRVDN_SHIFT 12 +#define PGRP_DRVDN_MASK (0x7F << PGRP_DRVDN_SHIFT) +#define PGRP_DRVUP_SHIFT 20 +#define PGRP_DRVUP_MASK (0x7F << PGRP_DRVUP_SHIFT) +#define PGRP_SLWR_SHIFT 28 +#define PGRP_SLWR_MASK (3 << PGRP_SLWR_SHIFT) +#define PGRP_SLWF_SHIFT 30 +#define PGRP_SLWF_MASK (3 << PGRP_SLWF_SHIFT) + /* Convenient macro for defining pin group properties */ #define PIN(pg_name, vdd, f0, f1, f2, f3, iod) \ { \ @@ -504,3 +517,178 @@ void pinmux_config_table(struct pingroup_config *config, int len) for (i = 0; i < len; i++) pinmux_config_pingroup(&config[i]); } + +static int padgrp_set_drvup_slwf(enum pdrive_pingrp pad, + int slwf) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwf = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwf */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwf)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwf == PGRP_SLWF_NONE) + return 0; + + reg = readl(pad_slwf); + reg &= ~PGRP_SLWF_MASK; + reg |= (slwf << PGRP_SLWF_SHIFT); + writel(reg, pad_slwf); + + return 0; +} + +static int padgrp_set_drvdn_slwr(enum pdrive_pingrp pad, int slwr) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwr = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwr */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwr)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwr == PGRP_SLWR_NONE) + return 0; + + reg = readl(pad_slwr); + reg &= ~PGRP_SLWR_MASK; + reg |= (slwr << PGRP_SLWR_SHIFT); + writel(reg, pad_slwr); + + return 0; +} + +static int padgrp_set_drvup(enum pdrive_pingrp pad, int drvup) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvup = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvup */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvup)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvup == PGRP_DRVUP_NONE) + return 0; + + reg = readl(pad_drvup); + reg &= ~PGRP_DRVUP_MASK; + reg |= (drvup << PGRP_DRVUP_SHIFT); + writel(reg, pad_drvup); + + return 0; +} + +static int padgrp_set_drvdn(enum pdrive_pingrp pad, int drvdn) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvdn = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvdn */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvdn)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvdn == PGRP_DRVDN_NONE) + return 0; + + reg = readl(pad_drvdn); + reg &= ~PGRP_DRVDN_MASK; + reg |= (drvdn << PGRP_DRVDN_SHIFT); + writel(reg, pad_drvdn); + + return 0; +} + +static int padgrp_set_lpmd(enum pdrive_pingrp pad, enum pgrp_lpmd lpmd) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_lpmd = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad and lpmd value */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_lpmd_isvalid(lpmd)); + + /* NONE means unspecified/do not change/use POR value */ + if (lpmd == PGRP_LPMD_NONE) + return 0; + + reg = readl(pad_lpmd); + reg &= ~PGRP_LPMD_MASK; + reg |= (lpmd << PGRP_LPMD_SHIFT); + writel(reg, pad_lpmd); + + return 0; +} + +static int padgrp_set_schmt(enum pdrive_pingrp pad, enum pgrp_schmt schmt) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_schmt = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + reg = readl(pad_schmt); + reg &= ~(1 << PGRP_SCHMT_SHIFT); + if (schmt == PGRP_SCHMT_ENABLE) + reg |= (0x1 << PGRP_SCHMT_SHIFT); + writel(reg, pad_schmt); + + return 0; +} +static int padgrp_set_hsm(enum pdrive_pingrp pad, + enum pgrp_hsm hsm) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_hsm = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + reg = readl(pad_hsm); + reg &= ~(1 << PGRP_HSM_SHIFT); + if (hsm == PGRP_HSM_ENABLE) + reg |= (0x1 << PGRP_HSM_SHIFT); + writel(reg, pad_hsm); + + return 0; +} + +void padctrl_config_pingroup(struct padctrl_config *config) +{ + enum pdrive_pingrp pad = config->padgrp; + + padgrp_set_drvup_slwf(pad, config->slwf); + padgrp_set_drvdn_slwr(pad, config->slwr); + padgrp_set_drvup(pad, config->drvup); + padgrp_set_drvdn(pad, config->drvdn); + padgrp_set_lpmd(pad, config->lpmd); + padgrp_set_schmt(pad, config->schmt); + padgrp_set_hsm(pad, config->hsm); +} + +void padgrp_config_table(struct padctrl_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) + padctrl_config_pingroup(&config[i]); +} -- cgit From b3b6ddff0bb6768af7532da4cee5362fbe41ec4b Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Wed, 13 Mar 2013 15:00:54 -0700 Subject: Tegra114: pinmux: Fix bad CAM_MCLK func 3 table entry This caused CAM_MCLK's pinmux reg to be locked out, since the table parsing code couldn't find a matching entry for VI_ALT3 and wrote garbage to the register. Signed-off-by: Tom Warren --- arch/arm/cpu/tegra114-common/pinmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/tegra114-common/pinmux.c b/arch/arm/cpu/tegra114-common/pinmux.c index 27b5f694fa..16368c5bc1 100644 --- a/arch/arm/cpu/tegra114-common/pinmux.c +++ b/arch/arm/cpu/tegra114-common/pinmux.c @@ -226,7 +226,7 @@ const struct tegra_pingroup_desc tegra_soc_pingroups[PINGRP_COUNT] = { PINI(SDMMC4_DAT6, SDMMC4, SDMMC4, SPI3, GMI, RSVD4), PINI(SDMMC4_DAT7, SDMMC4, SDMMC4, RSVD2, GMI, RSVD4), PIN_RESERVED, /* Reserved by t114: 0x3280 */ - PINI(CAM_MCLK, CAM, VI, VI_ALT1, VI_ALT2, RSVD4), + PINI(CAM_MCLK, CAM, VI, VI_ALT1, VI_ALT3, RSVD4), PINI(GPIO_PCC1, CAM, I2S4, RSVD2, RSVD3, RSVD4), PINI(GPIO_PBB0, CAM, I2S4, VI, VI_ALT1, VI_ALT3), PINI(CAM_I2C_SCL, CAM, VGP1, I2C3, RSVD3, RSVD4), -- cgit From 477393e7875cf4261f107fdfb8887309ea7fc3f7 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 11 Mar 2013 16:43:49 -0700 Subject: Tegra114: Dalmore: Add pad config tables/code based on pinmux code Pad config registers exist in APB_MISC_GP space, and control slew rate, drive strengh, schmidt, high-speed, and low-power modes for all of the pingroups in Tegra30. This builds off of the pinmux way of constructing init tables to configure select pads (SDIOCFG, for instance) during pinmux_init(). Currently, no padcfg entries exist. SDIO3CFG will be added when the MMC driver is added as per the TRM to work with the SD-card slot on Dalmore E1611. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/cpu/tegra114-common/pinmux.c | 194 ++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) (limited to 'arch/arm/cpu') diff --git a/arch/arm/cpu/tegra114-common/pinmux.c b/arch/arm/cpu/tegra114-common/pinmux.c index 16368c5bc1..4983a05090 100644 --- a/arch/arm/cpu/tegra114-common/pinmux.c +++ b/arch/arm/cpu/tegra114-common/pinmux.c @@ -39,6 +39,19 @@ struct tegra_pingroup_desc { #define PMUX_IO_RESET_SHIFT 8 #define PMUX_RCV_SEL_SHIFT 9 +#define PGRP_HSM_SHIFT 2 +#define PGRP_SCHMT_SHIFT 3 +#define PGRP_LPMD_SHIFT 4 +#define PGRP_LPMD_MASK (3 << PGRP_LPMD_SHIFT) +#define PGRP_DRVDN_SHIFT 12 +#define PGRP_DRVDN_MASK (0x7F << PGRP_DRVDN_SHIFT) +#define PGRP_DRVUP_SHIFT 20 +#define PGRP_DRVUP_MASK (0x7F << PGRP_DRVUP_SHIFT) +#define PGRP_SLWR_SHIFT 28 +#define PGRP_SLWR_MASK (3 << PGRP_SLWR_SHIFT) +#define PGRP_SLWF_SHIFT 30 +#define PGRP_SLWF_MASK (3 << PGRP_SLWF_SHIFT) + /* Convenient macro for defining pin group properties */ #define PIN(pg_name, vdd, f0, f1, f2, f3, iod) \ { \ @@ -544,3 +557,184 @@ void pinmux_config_table(struct pingroup_config *config, int len) for (i = 0; i < len; i++) pinmux_config_pingroup(&config[i]); } + +static int padgrp_set_drvup_slwf(enum pdrive_pingrp pad, int slwf) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwf = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwf */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwf)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwf == PGRP_SLWF_NONE) + return 0; + + reg = readl(pad_slwf); + reg &= ~PGRP_SLWF_MASK; + reg |= (slwf << PGRP_SLWF_SHIFT); + writel(reg, pad_slwf); + + return 0; +} + +static int padgrp_set_drvdn_slwr(enum pdrive_pingrp pad, int slwr) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_slwr = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and slwr */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_slw_isvalid(slwr)); + + /* NONE means unspecified/do not change/use POR value */ + if (slwr == PGRP_SLWR_NONE) + return 0; + + reg = readl(pad_slwr); + reg &= ~PGRP_SLWR_MASK; + reg |= (slwr << PGRP_SLWR_SHIFT); + writel(reg, pad_slwr); + + return 0; +} + +static int padgrp_set_drvup(enum pdrive_pingrp pad, int drvup) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvup = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvup */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvup)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvup == PGRP_DRVUP_NONE) + return 0; + + reg = readl(pad_drvup); + reg &= ~PGRP_DRVUP_MASK; + reg |= (drvup << PGRP_DRVUP_SHIFT); + writel(reg, pad_drvup); + + return 0; +} + +static int padgrp_set_drvdn(enum pdrive_pingrp pad, int drvdn) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_drvdn = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check on pad and drvdn */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_drv_isvalid(drvdn)); + + /* NONE means unspecified/do not change/use POR value */ + if (drvdn == PGRP_DRVDN_NONE) + return 0; + + reg = readl(pad_drvdn); + reg &= ~PGRP_DRVDN_MASK; + reg |= (drvdn << PGRP_DRVDN_SHIFT); + writel(reg, pad_drvdn); + + return 0; +} + +static int padgrp_set_lpmd(enum pdrive_pingrp pad, enum pgrp_lpmd lpmd) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_lpmd = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad and lpmd value */ + assert(pmux_padgrp_isvalid(pad)); + assert(pmux_pad_lpmd_isvalid(lpmd)); + + /* NONE means unspecified/do not change/use POR value */ + if (lpmd == PGRP_LPMD_NONE) + return 0; + + reg = readl(pad_lpmd); + reg &= ~PGRP_LPMD_MASK; + reg |= (lpmd << PGRP_LPMD_SHIFT); + writel(reg, pad_lpmd); + + return 0; +} + +static int padgrp_set_schmt(enum pdrive_pingrp pad, enum pgrp_schmt schmt) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_schmt = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + /* NONE means unspecified/do not change/use POR value */ + if (schmt == PGRP_SCHMT_NONE) + return 0; + + reg = readl(pad_schmt); + reg &= ~(1 << PGRP_SCHMT_SHIFT); + if (schmt == PGRP_SCHMT_ENABLE) + reg |= (0x1 << PGRP_SCHMT_SHIFT); + writel(reg, pad_schmt); + + return 0; +} +static int padgrp_set_hsm(enum pdrive_pingrp pad, enum pgrp_hsm hsm) +{ + struct pmux_tri_ctlr *pmt = + (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + u32 *pad_hsm = &pmt->pmt_drive[pad]; + u32 reg; + + /* Error check pad */ + assert(pmux_padgrp_isvalid(pad)); + + /* NONE means unspecified/do not change/use POR value */ + if (hsm == PGRP_HSM_NONE) + return 0; + + reg = readl(pad_hsm); + reg &= ~(1 << PGRP_HSM_SHIFT); + if (hsm == PGRP_HSM_ENABLE) + reg |= (0x1 << PGRP_HSM_SHIFT); + writel(reg, pad_hsm); + + return 0; +} + +void padctrl_config_pingroup(struct padctrl_config *config) +{ + enum pdrive_pingrp pad = config->padgrp; + + padgrp_set_drvup_slwf(pad, config->slwf); + padgrp_set_drvdn_slwr(pad, config->slwr); + padgrp_set_drvup(pad, config->drvup); + padgrp_set_drvdn(pad, config->drvdn); + padgrp_set_lpmd(pad, config->lpmd); + padgrp_set_schmt(pad, config->schmt); + padgrp_set_hsm(pad, config->hsm); +} + +void padgrp_config_table(struct padctrl_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) + padctrl_config_pingroup(&config[i]); +} -- cgit