blob: ed810bcf0fe8431e2eee767b7b4f2491e450a66b [file] [log] [blame]
/*
* 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);
}