271 lines
7.8 KiB
C
271 lines
7.8 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include "freq.h"
|
|
#include "reg.h"
|
|
#include "syscall-arom.h"
|
|
#include "cpu.h"
|
|
|
|
#include "log.h"
|
|
#define LOG_MODULE "Freq"
|
|
#define LOG_LEVEL LOG_LEVEL_MAIN
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* PMU AP register offset */
|
|
#define PMUA_CP_CPU_CLK_CTRL 0x10C
|
|
#define PMUA_ACLK_CTRL 0x144
|
|
|
|
/* CP CPU CLK Control register bit */
|
|
#define CP_CORE_ACLK_DIV_SHIFT 9
|
|
#define CP_CORE_MC_CLK_DIV_SHIFT 6
|
|
#define CP_CORE_PCLK_DIV_SHIFT 3
|
|
#define CP_CORE_PCLK_SEL_SHIFT 0
|
|
#define CP_CORE_CLK_FC_REQ (1 << 12)
|
|
|
|
/* ACLK Control register bit */
|
|
#define ACLK_FC_REQ (1 << 4)
|
|
#define ACLK_SEL_LEGACY (1 << 0)
|
|
#define ACLK_SEL (3 << 0)
|
|
|
|
/* PLL1 SW control register 2 */
|
|
#define APB_SPARE2_REG 0xD4090104
|
|
|
|
#define CLK_SEL_MASK 0x7
|
|
#define CLK_DIV_MASK 0x7
|
|
|
|
/* PLL1 SW control register 3 for watch1 cr5 */
|
|
#define SYS_PLL1_CTL3_REG (0x41000000 + 0x88)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
cr5_freq_change(unsigned pclk_sel, unsigned pclk_div)
|
|
{
|
|
unsigned val, mask;
|
|
unsigned aclk_div = 1, mc_clk_div = 1;
|
|
int i;
|
|
|
|
/* Enable PPL1 307, 350, 409, 491, 614, 819 */
|
|
writel(readl(APB_SPARE2_REG) | (0x3F), APB_SPARE2_REG);
|
|
|
|
mask = (CLK_SEL_MASK << CP_CORE_PCLK_SEL_SHIFT) |
|
|
(CLK_DIV_MASK << CP_CORE_MC_CLK_DIV_SHIFT) |
|
|
(CLK_DIV_MASK << CP_CORE_PCLK_DIV_SHIFT) |
|
|
(CLK_DIV_MASK << CP_CORE_ACLK_DIV_SHIFT);
|
|
|
|
val = readl(PMU_BASE + PMUA_CP_CPU_CLK_CTRL);
|
|
val &= ~mask;
|
|
val |= (pclk_sel << CP_CORE_PCLK_SEL_SHIFT) |
|
|
(pclk_div << CP_CORE_PCLK_DIV_SHIFT) |
|
|
(mc_clk_div << CP_CORE_MC_CLK_DIV_SHIFT) |
|
|
(aclk_div << CP_CORE_ACLK_DIV_SHIFT) |
|
|
CP_CORE_CLK_FC_REQ;
|
|
writel(val, PMU_BASE + PMUA_CP_CPU_CLK_CTRL);
|
|
|
|
for(i = 0; i < 100000; i++) {
|
|
val = readl(PMU_BASE + PMUA_CP_CPU_CLK_CTRL);
|
|
if((val & CP_CORE_CLK_FC_REQ) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(val & CP_CORE_CLK_FC_REQ) {
|
|
LOG_ERR("CR5 freq change failed\n");
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
axi_freq_change(unsigned int aclk_sel)
|
|
{
|
|
unsigned val;
|
|
int i;
|
|
|
|
val = readl(PMU_BASE + PMUA_ACLK_CTRL);
|
|
val &= ~ACLK_SEL;
|
|
val |= (aclk_sel & ACLK_SEL) | ACLK_FC_REQ;
|
|
writel(val, PMU_BASE + PMUA_ACLK_CTRL);
|
|
|
|
for(i = 0; i < 100000; i++) {
|
|
val = readl(PMU_BASE + PMUA_ACLK_CTRL);
|
|
if((val & ACLK_FC_REQ) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(val & ACLK_FC_REQ) {
|
|
LOG_ERR("AXI freq change failed\n");
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static bool
|
|
cr5_clk_legacy(void)
|
|
{
|
|
unsigned int chip_id = hw_chip_id();
|
|
|
|
return chip_id == CHIP_ID_CRANE ||
|
|
chip_id == CHIP_ID_CRANEG ||
|
|
chip_id == CHIP_ID_CRANEM ||
|
|
chip_id == CHIP_ID_CRANEL;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
static bool
|
|
axi_clk_legacy(void)
|
|
{
|
|
unsigned int chip_id = hw_chip_id();
|
|
|
|
return chip_id == CHIP_ID_CRANE ||
|
|
chip_id == CHIP_ID_CRANEG ||
|
|
chip_id == CHIP_ID_CRANEM ||
|
|
chip_id == CHIP_ID_CRANEL;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
/* pclk: CR5 clk; aclk AXI clk */
|
|
static const unsigned _cr5_clk[5] = { 409, 307, 491, 614, 819 };
|
|
static const unsigned _axi_clk[4] = { 154, 205, 189, 223 };
|
|
static const unsigned _cr5_clk_legacy[5] = { 416, 312, 499, 624, 832 };
|
|
static const unsigned _axi_clk_legacy[2] = { 156, 208 };
|
|
/* craneGT/craneLRH/CraneGD axi clock config are different from craneLS/LR/LG/LB etc. */
|
|
static const unsigned _axi_clk_cranelrh_gt[4] = { 223, 189, 154, 205 };
|
|
/* Lapwing axi clock config. */
|
|
static const unsigned _axi_clk_lapwing[4] = { 156, 208, 192, 312 };
|
|
/*---------------------------------------------------------------------------*/
|
|
int
|
|
get_curr_freq(unsigned *ppclk, unsigned *paclk)
|
|
{
|
|
unsigned cr5_val, axi_val, clk_sel, pclk_div;
|
|
const unsigned *cr5_clk, *axi_clk;
|
|
|
|
cr5_clk = cr5_clk_legacy() ? _cr5_clk_legacy : _cr5_clk;
|
|
|
|
cr5_val = readl(PMU_BASE + PMUA_CP_CPU_CLK_CTRL);
|
|
clk_sel = cr5_val & CLK_SEL_MASK;
|
|
pclk_div = (cr5_val >> CP_CORE_PCLK_DIV_SHIFT) & CLK_DIV_MASK;
|
|
|
|
if(clk_sel > 4) {
|
|
LOG_ERR("get_curr_freq failed, Invalid clk_sel, 0x%x = 0x%x \n",
|
|
PMU_BASE + PMUA_CP_CPU_CLK_CTRL, cr5_val);
|
|
return -1;
|
|
} else if(clk_sel == 4) {
|
|
*ppclk = cr5_clk[clk_sel];
|
|
} else {
|
|
*ppclk = cr5_clk[clk_sel] / (1 + pclk_div);
|
|
}
|
|
|
|
axi_val = readl(PMU_BASE + PMUA_ACLK_CTRL);
|
|
unsigned int chipid = hw_chip_id();
|
|
if(chipid == CHIP_ID_CRANELRH || chipid == CHIP_ID_CRANEGT
|
|
|| chipid == CHIP_ID_CRANEGD) {
|
|
axi_clk = _axi_clk_cranelrh_gt;
|
|
*paclk = axi_clk[axi_val & ACLK_SEL];
|
|
} else if(chipid == CHIP_ID_LAPWING) {
|
|
axi_clk = _axi_clk_lapwing;
|
|
*paclk = axi_clk[axi_val & ACLK_SEL];
|
|
} else if(axi_clk_legacy()) {
|
|
axi_clk = _axi_clk_legacy;
|
|
*paclk = axi_clk[axi_val & ACLK_SEL_LEGACY];
|
|
} else {
|
|
axi_clk = _axi_clk;
|
|
*paclk = axi_clk[axi_val & ACLK_SEL];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
#define CR5_PCLK_SEL_DEFAULT 0
|
|
#define AXI_FREQ_DEFAULT 0
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
cr5_axi_set_default_freq(void)
|
|
{
|
|
unsigned pclk_old, aclk_old, pclk, aclk;
|
|
|
|
if(get_curr_freq(&pclk_old, &aclk_old) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
/*
|
|
* axi_clk_legacy(): CraneG/M/L
|
|
*/
|
|
unsigned int chip_id = hw_chip_id();
|
|
if(axi_clk_legacy() || chip_id == CHIP_ID_CRANELRH) {
|
|
/*
|
|
* keep max freq with 20240223 version, and don't restore default value.
|
|
*
|
|
* CraneG/M/L: 208MHz
|
|
* CraneLRH: 223MHz
|
|
*/
|
|
} else if(chip_id == CHIP_ID_CRANELR || chip_id == CHIP_ID_CRANELS) {
|
|
/*
|
|
* keep max freq with 20240223 version
|
|
*
|
|
* CraneLR/LS: 205MHz
|
|
*/
|
|
axi_freq_change(AXI_FREQ_208M);
|
|
} else if(chip_id == CHIP_ID_CRANELG) {
|
|
/*
|
|
* keep max freq with 20240223 version
|
|
*
|
|
* CraneLG 154MHz
|
|
*/
|
|
axi_freq_change(AXI_FREQ_156M);
|
|
} else {
|
|
cr5_freq_change(CR5_PCLK_SEL_DEFAULT, CR5_PCLK_DIV_0);
|
|
axi_freq_change(AXI_FREQ_DEFAULT);
|
|
}
|
|
|
|
if(get_curr_freq(&pclk, &aclk) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
LOG_INFO("Freq change restore done: CR5 %uMHz -> %uMHz, AXI %uMHz -> %uMHz\n",
|
|
pclk_old, pclk, aclk_old, aclk);
|
|
return;
|
|
error:
|
|
LOG_ERR("%s failed\n", __func__);
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
void
|
|
cr5_axi_set_max_freq(void)
|
|
{
|
|
unsigned pclk_old, aclk_old, pclk, aclk;
|
|
|
|
if(get_curr_freq(&pclk_old, &aclk_old) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
cr5_freq_change(CR5_PCLK_SEL_624, CR5_PCLK_DIV_0); /* CR5 624MHz or 614MHZ for newer chip */
|
|
|
|
unsigned freq_max;
|
|
unsigned int chipid = hw_chip_id();
|
|
if(chipid == CHIP_ID_CRANELRH || chipid == CHIP_ID_CRANEGT
|
|
|| chipid == CHIP_ID_CRANEGD) {
|
|
freq_max = AXI_FREQ_223M_LRH_GT;
|
|
} else if((chipid == CHIP_ID_LAPWING)) {
|
|
/* enable PLL1 DIV2, DIV23, DIV13, DIV11 */
|
|
writel(readl(APB_SPARE12_REG) | (1 << 16 | 1 << 17 | 1 << 18 | 1 << 19), APB_SPARE12_REG);
|
|
freq_max = AXI_FREQ_312M;
|
|
} else if(axi_clk_legacy()) {
|
|
freq_max = AXI_FREQ_208M;
|
|
} else if(chipid == CHIP_ID_WATCH1 || chipid == CHIP_ID_WATCH_TWO) {
|
|
/* enable PLL1 DIV11, DIV13, DIV23 for watch1, watch2 cr5*/
|
|
writel(readl(SYS_PLL1_CTL3_REG) | (0x7 << 13), SYS_PLL1_CTL3_REG);
|
|
freq_max = AXI_FREQ_223M;
|
|
} else {
|
|
/* enable PLL1 DIV11, DIV13, DIV23 */
|
|
writel(readl(APB_SPARE12_REG) | 0x7, APB_SPARE12_REG);
|
|
freq_max = AXI_FREQ_223M;
|
|
}
|
|
|
|
axi_freq_change(freq_max);
|
|
|
|
if(get_curr_freq(&pclk, &aclk) < 0) {
|
|
goto error;
|
|
}
|
|
|
|
LOG_INFO("Freq change done: CR5 %uMHz -> %uMHz, AXI %uMHz -> %uMHz\n",
|
|
pclk_old, pclk, aclk_old, aclk);
|
|
return;
|
|
error:
|
|
LOG_ERR("cr5_axi_set_max_freq failed\n");
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|