/* * Function: sdhci set SDR mode * Arg : Host structure * Return : None * Flow: : 1. Disable the clock * 2. Enable sdr mode * 3. Enable the clock * Details : SDR50/SDR104 mode is nothing but HS200 * mode SDCC spec refers to it as SDR mode * & emmc spec refers as HS200 mode. */ void sdhci_set_sdr_mode(struct sdhci_host *host) { uint16_t clk; uint16_t ctrl = 0; /* Disable the clock */ clk = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk &= ~SDHCI_CLK_EN; REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG); /* Enable SDR50 mode: * Right now we support only SDR50 mode which runs at * 100 MHZ sdcc clock, we dont need tuning with SDR50 * mode */ ctrl = REG_READ16(host, SDHCI_HOST_CTRL2_REG); /* Enable SDR50/SDR104 mode based on the controller * capabilities. */ if (host->caps.sdr50_support) ctrl |= SDHCI_SDR50_MODE_EN; REG_WRITE16(host, ctrl, SDHCI_HOST_CTRL2_REG); /* Run the clock back */ sdhci_clk_supply(host, SDHCI_CLK_100MHZ); }
/** * usb_hub_init - initialises and resets the external USB hub * * The USB hub needs to be held in reset while the power is being applied * and the reference clock is enabled at 19.2MHz. The following is the * layout of the USB hub taken from the Pandaboard reference manual. * * * .-------------. .--------------. .----------------. * | OMAP4430 | | USB3320C | | LAN9514 | * | | | | | USB Hub / Eth | * | CLK | <------ | CLKOUT | | | * | STP | ------> | STP | | | * | DIR | <------ | DIR | | | * | NXT | <------ | NXT | | | * | DAT0 | <-----> | DAT0 | | | * | DAT1 | <-----> | DAT1 DP | <-----> | DP | * | DAT2 | <-----> | DAT2 DM | <-----> | DM | * | DAT3 | <-----> | DAT3 | | | * | DAT4 | <-----> | DAT4 | | | * | DAT5 | <-----> | DAT5 | +----> | N_RESET | * | DAT6 | <-----> | DAT6 | | | | * | DAT7 | <-----> | DAT7 | | | | * | | | | | +-> | VDD33IO | * | AUX_CLK3 | ------> | REFCLK | | +-> | VDD33A | * | | | | | | | | * | GPIO_62 | --+---> | RESET | | | | | * | | | | | | | | | * | | | '--------------' | | '----------------' * | | | .--------------. | | * | | '---->| VOLT CONVERT |--' | * | | '--------------' | * | | | * | | .--------------. | * | GPIO_1 | ------> | TPS73633 |-----' * | | '--------------' * '-------------' * * * RETURNS: * nothing. */ static void usb_hub_init(void) { bus_space_handle_t scrm_addr, gpio1_addr, gpio2_addr, scm_addr; if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCRM_HWBASE, OMAP44XX_SCRM_SIZE, 0, &scrm_addr) != 0) panic("Couldn't map SCRM registers"); if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO1_HWBASE, OMAP44XX_GPIO1_SIZE, 0, &gpio1_addr) != 0) panic("Couldn't map GPIO1 registers"); if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO2_HWBASE, OMAP44XX_GPIO2_SIZE, 0, &gpio2_addr) != 0) panic("Couldn't map GPIO2 registers"); if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCM_PADCONF_HWBASE, OMAP44XX_SCM_PADCONF_SIZE, 0, &scm_addr) != 0) panic("Couldn't map SCM Padconf registers"); /* Need to set FREF_CLK3_OUT to 19.2 MHz and pump it out on pin GPIO_WK31. * We know the SYS_CLK is 38.4Mhz and therefore to get the needed 19.2Mhz, * just use a 2x divider and ensure the SYS_CLK is used as the source. */ REG_WRITE32(scrm_addr + SCRM_AUXCLK3, (1 << 16) | /* Divider of 2 */ (0 << 1) | /* Use the SYS_CLK as the source */ (1 << 8)); /* Enable the clock */ /* Enable the clock out to the pin (GPIO_WK31). * muxmode=fref_clk3_out, pullup/down=disabled, input buffer=disabled, * wakeup=disabled. */ REG_WRITE16(scm_addr + CONTROL_WKUP_PAD0_FREF_CLK3_OUT, 0x0000); /* Disable the power to the USB hub, drive GPIO1 low */ REG_WRITE32(gpio1_addr + GPIO1_OE, REG_READ32(gpio1_addr + GPIO1_OE) & ~(1UL << 1)); REG_WRITE32(gpio1_addr + GPIO1_CLEARDATAOUT, (1UL << 1)); REG_WRITE16(scm_addr + CONTROL_CORE_PAD1_KPD_COL2, 0x0003); /* Reset the USB PHY and Hub using GPIO_62 */ REG_WRITE32(gpio2_addr + GPIO2_OE, REG_READ32(gpio2_addr + GPIO2_OE) & ~(1UL << 30)); REG_WRITE32(gpio2_addr + GPIO2_CLEARDATAOUT, (1UL << 30)); REG_WRITE16(scm_addr + CONTROL_CORE_PAD0_GPMC_WAIT1, 0x0003); DELAY(10); REG_WRITE32(gpio2_addr + GPIO2_SETDATAOUT, (1UL << 30)); /* Enable power to the hub (GPIO_1) */ REG_WRITE32(gpio1_addr + GPIO1_SETDATAOUT, (1UL << 1)); bus_space_unmap(fdtbus_bs_tag, scrm_addr, OMAP44XX_SCRM_SIZE); bus_space_unmap(fdtbus_bs_tag, gpio1_addr, OMAP44XX_GPIO1_SIZE); bus_space_unmap(fdtbus_bs_tag, gpio2_addr, OMAP44XX_GPIO2_SIZE); bus_space_unmap(fdtbus_bs_tag, scm_addr, OMAP44XX_SCM_PADCONF_SIZE); }
/* * Function: sdhci error status enable * Arg : Host structure * Return : None * Flow: : Enable command error status */ static void sdhci_error_status_enable(struct sdhci_host *host) { /* Enable all interrupt status */ REG_WRITE16(host, SDHCI_NRML_INT_STS_EN, SDHCI_NRML_INT_STS_EN_REG); REG_WRITE16(host, SDHCI_ERR_INT_STS_EN, SDHCI_ERR_INT_STS_EN_REG); /* Enable all interrupt signal */ REG_WRITE16(host, SDHCI_NRML_INT_SIG_EN, SDHCI_NRML_INT_SIG_EN_REG); REG_WRITE16(host, SDHCI_ERR_INT_SIG_EN, SDHCI_ERR_INT_SIG_EN_REG); }
/* * Function: sdhci clock supply * Arg : Host structure * Return : 0 on Success, 1 on Failure * Flow: : 1. Calculate the clock divider * 2. Set the clock divider * 3. Check if clock stable * 4. Enable Clock */ uint32_t sdhci_clk_supply(struct sdhci_host *host, uint32_t clk) { uint32_t div = 0; uint32_t freq = 0; uint16_t clk_val = 0; if (clk > host->caps.base_clk_rate) { dprintf(CRITICAL, "Error: Requested clk freq is more than supported\n"); return 1; } if (clk == host->caps.base_clk_rate) goto clk_ctrl; /* As per the sd spec div should be a multiplier of 2 */ for (div = 2; div < SDHCI_CLK_MAX_DIV; div += 2) { freq = host->caps.base_clk_rate / div; if (freq <= clk) break; } div >>= 1; clk_ctrl: /* As per the sdhci spec 3.0, bits 6-7 of the clock * control registers will be mapped to bit 8-9, to * support a 10 bit divider value. * This is needed when the divider value overflows * the 8 bit range. */ clk_val = ((div & SDHCI_SDCLK_FREQ_MASK) << SDHCI_SDCLK_FREQ_SEL); clk_val |= ((div & SDHC_SDCLK_UP_BIT_MASK) >> SDHCI_SDCLK_FREQ_SEL) << SDHCI_SDCLK_UP_BIT_SEL; clk_val |= SDHCI_INT_CLK_EN; REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG); /* Check for clock stable */ while (!(REG_READ16(host, SDHCI_CLK_CTRL_REG) & SDHCI_CLK_STABLE)); /* Now clock is stable, enable it */ clk_val = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk_val |= SDHCI_CLK_EN; REG_WRITE16(host, clk_val, SDHCI_CLK_CTRL_REG); host->cur_clk_rate = freq; return 0; }
/* * Function: sdhci set ddr mode * Arg : Host structure * Return : None * Flow: : 1. Disable the clock * 2. Enable DDR mode * 3. Enable the clock */ void sdhci_set_ddr_mode(struct sdhci_host *host) { uint16_t clk; uint16_t ctrl = 0; /* Disable the clock */ clk = REG_READ16(host, SDHCI_CLK_CTRL_REG); clk &= ~SDHCI_CLK_EN; REG_WRITE16(host, clk, SDHCI_CLK_CTRL_REG); ctrl = REG_READ16(host, SDHCI_HOST_CTRL2_REG); ctrl |= SDHCI_DDR_MODE_EN; /* Enalbe DDR mode */ REG_WRITE16(host, ctrl, SDHCI_HOST_CTRL2_REG); /* Run the clock back */ sdhci_clk_supply(host, host->cur_clk_rate); }
/* * Function: sdhci stop sdcc clock * Arg : Host structure * Return : 0 on Success, 1 on Failure * Flow: : 1. Stop the clock */ static uint32_t sdhci_stop_sdcc_clk(struct sdhci_host *host) { uint32_t reg; reg = REG_READ32(host, SDHCI_PRESENT_STATE_REG); if (reg & (SDHCI_CMD_ACT | SDHCI_DAT_ACT)) { dprintf(CRITICAL, "Error: SDCC command & data line are active\n"); return 1; } REG_WRITE16(host, SDHCI_CLK_DIS, SDHCI_CLK_CTRL_REG); return 0; }
/* * Function: sdhci command complete * Arg : Host & command structure * Return : 0 on Sucess, 1 on Failure * Flow: : 1. Check for command complete * 2. Check for transfer complete * 3. Get the command response * 4. Check for errors */ static uint8_t sdhci_cmd_complete(struct sdhci_host *host, struct mmc_command *cmd) { uint8_t i; uint32_t retry = 0; uint32_t int_status; do { int_status = REG_READ16(host, SDHCI_NRML_INT_STS_REG); int_status &= SDHCI_INT_STS_CMD_COMPLETE; if (int_status == SDHCI_INT_STS_CMD_COMPLETE) break; retry++; udelay(500); if (retry == SDHCI_MAX_CMD_RETRY) { dprintf(CRITICAL, "Error: Command never completed\n"); goto err; } } while(1); /* Command is complete, clear the interrupt bit */ REG_WRITE16(host, SDHCI_INT_STS_CMD_COMPLETE, SDHCI_NRML_INT_STS_REG); /* Copy the command response, * The valid bits for R2 response are 0-119, & but the actual response * is stored in bits 8-128. We need to move 8 bits of MSB of each * response to register 8 bits of LSB of next response register. * As: * MSB 8 bits of RESP0 --> LSB 8 bits of RESP1 * MSB 8 bits of RESP1 --> LSB 8 bits of RESP2 * MSB 8 bits of RESP2 --> LSB 8 bits of RESP3 */ if (cmd->resp_type == SDHCI_CMD_RESP_R2) { for (i = 0; i < 4; i++) { cmd->resp[i] = REG_READ32(host, SDHCI_RESP_REG + (i * 4)); cmd->resp[i] <<= SDHCI_RESP_LSHIFT; if (i != 0) cmd->resp[i] |= (REG_READ32(host, SDHCI_RESP_REG + ((i-1) * 4)) >> SDHCI_RESP_RSHIFT); } } else