2f37bd6551
This patch is a raw application of the following spatch to src/: @@ expression A, V; @@ - writel(V, A) + write32(A, V) @@ expression A, V; @@ - writew(V, A) + write16(A, V) @@ expression A, V; @@ - writeb(V, A) + write8(A, V) @@ expression A; @@ - readl(A) + read32(A) @@ expression A; @@ - readb(A) + read8(A) BRANCH=none BUG=chromium:444723 TEST=None (depends on next patch) Change-Id: I5dd96490c85ee2bcbc669f08bc6fff0ecc0f9e27 Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: 64f643da95d85954c4d4ea91c34a5c69b9b08eb6 Original-Change-Id: I366a2eb5b3a0df2279ebcce572fe814894791c42 Original-Signed-off-by: Julius Werner <jwerner@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/254864 Reviewed-on: http://review.coreboot.org/9836 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
316 lines
8.3 KiB
C
316 lines
8.3 KiB
C
/*
|
|
* Copyright (c) 2015, 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:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * 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.
|
|
* * Neither the name of The Linux Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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 <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <delay.h>
|
|
#include <console/console.h>
|
|
#include <soc/clock.h>
|
|
#include <soc/lcc-reg.h>
|
|
#include <arch/io.h>
|
|
|
|
typedef struct {
|
|
void *gcc_apcs_regs;
|
|
void *lcc_pll0_regs;
|
|
void *lcc_ahbix_regs;
|
|
void *lcc_mi2s_regs;
|
|
void *lcc_pll_regs;
|
|
} Ipq806xLccClocks;
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t apcs;
|
|
} Ipq806xLccGccRegs;
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t mode;
|
|
uint32_t l_val;
|
|
uint32_t m_val;
|
|
uint32_t n_val;
|
|
uint32_t UNUSED;
|
|
uint32_t config;
|
|
uint32_t status;
|
|
} Ipq806xLccPll0Regs;
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t ns;
|
|
uint32_t md;
|
|
uint32_t UNUSED;
|
|
uint32_t status;
|
|
} Ipq806xLccAhbixRegs;
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t ns;
|
|
uint32_t md;
|
|
uint32_t status;
|
|
} Ipq806xLccMi2sRegs;
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
uint32_t pri;
|
|
uint32_t sec;
|
|
} Ipq806xLccPllRegs;
|
|
|
|
struct lcc_freq_tbl {
|
|
unsigned freq;
|
|
unsigned pd;
|
|
unsigned m;
|
|
unsigned n;
|
|
unsigned d;
|
|
};
|
|
|
|
static const struct lcc_freq_tbl lcc_mi2s_freq_tbl[] = {
|
|
{ 1024000, 4, 1, 96, 8 },
|
|
{ 1411200, 4, 2, 139, 8 },
|
|
{ 1536000, 4, 1, 64, 8 },
|
|
{ 2048000, 4, 1, 48, 8 },
|
|
{ 2116800, 4, 2, 93, 8 },
|
|
{ 2304000, 4, 2, 85, 8 },
|
|
{ 2822400, 4, 6, 209, 8 },
|
|
{ 3072000, 4, 1, 32, 8 },
|
|
{ 3175200, 4, 1, 31, 8 },
|
|
{ 4096000, 4, 1, 24, 8 },
|
|
{ 4233600, 4, 9, 209, 8 },
|
|
{ 4608000, 4, 3, 64, 8 },
|
|
{ 5644800, 4, 12, 209, 8 },
|
|
{ 6144000, 4, 1, 16, 8 },
|
|
{ 6350400, 4, 2, 31, 8 },
|
|
{ 8192000, 4, 1, 12, 8 },
|
|
{ 8467200, 4, 18, 209, 8 },
|
|
{ 9216000, 4, 3, 32, 8 },
|
|
{ 11289600, 4, 24, 209, 8 },
|
|
{ 12288000, 4, 1, 8, 8 },
|
|
{ 12700800, 4, 27, 209, 8 },
|
|
{ 13824000, 4, 9, 64, 8 },
|
|
{ 16384000, 4, 1, 6, 8 },
|
|
{ 16934400, 4, 41, 238, 8 },
|
|
{ 18432000, 4, 3, 16, 8 },
|
|
{ 22579200, 2, 24, 209, 8 },
|
|
{ 24576000, 4, 1, 4, 8 },
|
|
{ 27648000, 4, 9, 32, 8 },
|
|
{ 33868800, 4, 41, 119, 8 },
|
|
{ 36864000, 4, 3, 8, 8 },
|
|
{ 45158400, 1, 24, 209, 8 },
|
|
{ 49152000, 4, 1, 2, 8 },
|
|
{ 50803200, 1, 27, 209, 8 },
|
|
{ }
|
|
};
|
|
|
|
static int lcc_init_enable_pll0(Ipq806xLccClocks *bus)
|
|
{
|
|
Ipq806xLccGccRegs *gcc_regs = bus->gcc_apcs_regs;
|
|
Ipq806xLccPll0Regs *pll0_regs = bus->lcc_pll0_regs;
|
|
Ipq806xLccPllRegs *pll_regs = bus->lcc_pll_regs;
|
|
uint32_t regval;
|
|
|
|
regval = 0;
|
|
regval = 15 << LCC_PLL0_L_SHIFT & LCC_PLL0_L_MASK;
|
|
write32(&pll0_regs->l_val, regval);
|
|
|
|
regval = 0;
|
|
regval = 145 << LCC_PLL0_M_SHIFT & LCC_PLL0_M_MASK;
|
|
write32(&pll0_regs->m_val, regval);
|
|
|
|
regval = 0;
|
|
regval = 199 << LCC_PLL0_N_SHIFT & LCC_PLL0_N_MASK;
|
|
write32(&pll0_regs->n_val, regval);
|
|
|
|
regval = 0;
|
|
regval |= LCC_PLL0_CFG_LV_MAIN_ENABLE;
|
|
regval |= LCC_PLL0_CFG_FRAC_ENABLE;
|
|
write32(&pll0_regs->config, regval);
|
|
|
|
regval = 0;
|
|
regval |= LCC_PLL_PCLK_SRC_PRI;
|
|
write32(&pll_regs->pri, regval);
|
|
|
|
regval = 0;
|
|
regval |= 1 << LCC_PLL0_MODE_BIAS_CNT_SHIFT &
|
|
LCC_PLL0_MODE_BIAS_CNT_MASK;
|
|
regval |= 8 << LCC_PLL0_MODE_LOCK_CNT_SHIFT &
|
|
LCC_PLL0_MODE_LOCK_CNT_MASK;
|
|
write32(&pll0_regs->mode, regval);
|
|
|
|
regval = read32(&gcc_regs->apcs);
|
|
regval |= GCC_PLL_APCS_PLL4_ENABLE;
|
|
write32(&gcc_regs->apcs, regval);
|
|
|
|
regval = read32(&pll0_regs->mode);
|
|
regval |= LCC_PLL0_MODE_FSM_VOTE_ENABLE;
|
|
write32(&pll0_regs->mode, regval);
|
|
|
|
mdelay(1);
|
|
|
|
regval = read32(&pll0_regs->status);
|
|
if (regval & LCC_PLL0_STAT_ACTIVE_MASK)
|
|
return 0;
|
|
|
|
printk(BIOS_ERR, "%s: error enabling PLL4 clock\n", __func__);
|
|
return 1;
|
|
}
|
|
|
|
static int lcc_init_enable_ahbix(Ipq806xLccClocks *bus)
|
|
{
|
|
Ipq806xLccAhbixRegs *ahbix_regs = bus->lcc_ahbix_regs;
|
|
uint32_t regval;
|
|
|
|
regval = 0;
|
|
regval |= 1 << LCC_AHBIX_MD_M_VAL_SHIFT & LCC_AHBIX_MD_M_VAL_MASK;
|
|
regval |= 252 << LCC_AHBIX_MD_NOT_2D_VAL_SHIFT &
|
|
LCC_AHBIX_MD_NOT_2D_VAL_MASK;
|
|
write32(&ahbix_regs->md, regval);
|
|
|
|
regval = 0;
|
|
regval |= 253 << LCC_AHBIX_NS_N_VAL_SHIFT & LCC_AHBIX_NS_N_VAL_MASK;
|
|
regval |= LCC_AHBIX_NS_CRC_ENABLE;
|
|
regval |= LCC_AHBIX_NS_GFM_SEL_MNC;
|
|
regval |= LCC_AHBIX_NS_MNC_CLK_ENABLE;
|
|
regval |= LCC_AHBIX_NS_MNC_ENABLE;
|
|
regval |= LCC_AHBIX_NS_MNC_MODE_DUAL;
|
|
regval |= LCC_AHBIX_NS_PREDIV_BYPASS;
|
|
regval |= LCC_AHBIX_NS_MN_SRC_LPA;
|
|
write32(&ahbix_regs->ns, regval);
|
|
|
|
mdelay(1);
|
|
|
|
regval = read32(&ahbix_regs->status);
|
|
if (regval & LCC_AHBIX_STAT_AIF_CLK_MASK)
|
|
return 0;
|
|
|
|
printk(BIOS_ERR, "%s: error enabling AHBIX clock\n", __func__);
|
|
return 1;
|
|
}
|
|
|
|
static int lcc_init_mi2s(Ipq806xLccClocks *bus, unsigned freq)
|
|
{
|
|
Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
|
|
uint32_t regval;
|
|
uint8_t pd, m, n, d;
|
|
unsigned i;
|
|
|
|
i = 0;
|
|
while (lcc_mi2s_freq_tbl[i].freq != 0) {
|
|
if (lcc_mi2s_freq_tbl[i].freq == freq)
|
|
break;
|
|
++i;
|
|
}
|
|
if (lcc_mi2s_freq_tbl[i].freq == 0) {
|
|
printk(BIOS_ERR, "%s: invalid frequency given: %u\n",
|
|
__func__, freq);
|
|
return 1;
|
|
}
|
|
|
|
switch (lcc_mi2s_freq_tbl[i].pd) {
|
|
case 1:
|
|
pd = LCC_MI2S_NS_PREDIV_BYPASS;
|
|
break;
|
|
case 2:
|
|
pd = LCC_MI2S_NS_PREDIV_DIV2;
|
|
break;
|
|
case 4:
|
|
pd = LCC_MI2S_NS_PREDIV_DIV4;
|
|
break;
|
|
default:
|
|
printk(BIOS_ERR, "%s: invalid prediv found: %u\n", __func__,
|
|
lcc_mi2s_freq_tbl[i].pd);
|
|
return 1;
|
|
}
|
|
|
|
m = lcc_mi2s_freq_tbl[i].m;
|
|
n = ~(lcc_mi2s_freq_tbl[i].n - m);
|
|
d = ~(lcc_mi2s_freq_tbl[i].d * 2);
|
|
|
|
regval = 0;
|
|
regval |= m << LCC_MI2S_MD_M_VAL_SHIFT & LCC_MI2S_MD_M_VAL_MASK;
|
|
regval |= d << LCC_MI2S_MD_NOT_2D_VAL_SHIFT &
|
|
LCC_MI2S_MD_NOT_2D_VAL_MASK;
|
|
write32(&mi2s_regs->md, regval);
|
|
|
|
regval = 0;
|
|
regval |= n << LCC_MI2S_NS_N_VAL_SHIFT & LCC_MI2S_NS_N_VAL_MASK;
|
|
regval |= LCC_MI2S_NS_BIT_DIV_DIV4;
|
|
regval |= LCC_MI2S_NS_MNC_CLK_ENABLE;
|
|
regval |= LCC_MI2S_NS_MNC_ENABLE;
|
|
regval |= LCC_MI2S_NS_MNC_MODE_DUAL;
|
|
regval |= pd;
|
|
regval |= LCC_MI2S_NS_MN_SRC_LPA;
|
|
write32(&mi2s_regs->ns, regval);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lcc_enable_mi2s(Ipq806xLccClocks *bus)
|
|
{
|
|
Ipq806xLccMi2sRegs *mi2s_regs = bus->lcc_mi2s_regs;
|
|
uint32_t regval;
|
|
|
|
regval = read32(&mi2s_regs->ns);
|
|
regval |= LCC_MI2S_NS_OSR_CXC_ENABLE;
|
|
regval |= LCC_MI2S_NS_BIT_CXC_ENABLE;
|
|
write32(&mi2s_regs->ns, regval);
|
|
|
|
udelay(10);
|
|
|
|
regval = read32(&mi2s_regs->status);
|
|
if (regval & LCC_MI2S_STAT_OSR_CLK_MASK)
|
|
if (regval & LCC_MI2S_STAT_BIT_CLK_MASK)
|
|
return 0;
|
|
|
|
printk(BIOS_ERR, "%s: error enabling MI2S clocks: %u\n",
|
|
__func__, regval);
|
|
return 1;
|
|
}
|
|
|
|
int audio_clock_config(unsigned frequency)
|
|
{
|
|
Ipq806xLccClocks *bus = malloc(sizeof(*bus));
|
|
|
|
if (!bus) {
|
|
printk(BIOS_ERR, "%s: failed to allocate bus structure\n",
|
|
__func__);
|
|
return 1;
|
|
}
|
|
|
|
bus->gcc_apcs_regs = (void *)(MSM_GCC_BASE + GCC_PLL_APCS_REG);
|
|
bus->lcc_pll0_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL0_MODE_REG);
|
|
bus->lcc_ahbix_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_AHBIX_NS_REG);
|
|
bus->lcc_mi2s_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_MI2S_NS_REG);
|
|
bus->lcc_pll_regs = (void *)(MSM_LPASS_LCC_BASE + LCC_PLL_PCLK_REG);
|
|
|
|
|
|
if (lcc_init_enable_pll0(bus))
|
|
return 1;
|
|
if (lcc_init_enable_ahbix(bus))
|
|
return 1;
|
|
if (lcc_init_mi2s(bus, frequency))
|
|
return 1;
|
|
|
|
if (lcc_enable_mi2s(bus))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|