| /* |
| * Copyright (C) 2014 The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include <libpayload.h> |
| #include "drivers/storage/ipq806x_clocks.h" |
| #include "drivers/storage/ipq806x_mmc.h" |
| |
| void clock_init_mmc(unsigned instance) |
| { |
| /* Enable h/w gating */ |
| writel(1<<6, SDCn_HCLK_CTL_REG(instance)); |
| } |
| |
| static void clock_set_m_n_d(uint32_t instance, uint32_t m, |
| uint32_t n, uint32_t d, |
| uint32_t s, uint32_t pre) |
| { |
| uint32_t reg; |
| |
| reg = 2 * d; |
| reg = ~reg; |
| reg &= 0xFF; |
| |
| reg |= (m << 16); |
| writel(reg, SDCn_APPS_CLK_MD_REG(instance)); |
| |
| reg = (((~(n-m)) << 16) & 0xFFFF0000)|1<<11|s; |
| writel(reg, SDCn_APPS_CLK_NS_REG(instance)); |
| |
| /* enable m n d counters. */ |
| reg |= (2 << 5) | (pre << 3); |
| writel(reg, SDCn_APPS_CLK_NS_REG(instance)); |
| |
| reg |= (1 << 8); |
| writel(reg, SDCn_APPS_CLK_NS_REG(instance)); |
| |
| /* enable clock */ |
| writel(reg | 1<<9, SDCn_APPS_CLK_NS_REG(instance)); |
| } |
| |
| void clock_config_mmc(MmcCtrlr *ctrlr, unsigned freq) |
| { |
| uint32_t m, n, d, s, pre; |
| uint32_t reg; |
| QcomMmcHost *mmc_host = container_of(ctrlr, QcomMmcHost, mmc); |
| uint32_t instance = mmc_host->instance; |
| |
| /*Disable the clk */ |
| reg = readl(SDCn_APPS_CLK_NS_REG(instance)); |
| reg &= ~(1<<9); |
| writel(reg, SDCn_APPS_CLK_NS_REG(instance)); |
| |
| switch (freq) { |
| case 144000: |
| m = 2; |
| n = 125; |
| d = 3; |
| s = 0; |
| pre = 2; |
| break; |
| |
| case 400000: |
| m = 1; |
| n = 240; |
| d = 4; |
| s = 3; |
| pre = 3; |
| break; |
| |
| case 48000000: |
| case 52000000: |
| m = 1; |
| n = 2; |
| d = 1; |
| s = 3; |
| pre = 3; |
| break; |
| |
| default: |
| printf("MMC clock speed not supported %d\n", freq); |
| return; |
| } |
| |
| clock_set_m_n_d(instance, m, n, d, s, pre); |
| |
| mmc_boot_mci_clk_enable(ctrlr); |
| } |