GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Marvell International Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* https://spdx.org/licenses
|
||||
*/
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <errno.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <mvebu.h>
|
||||
#include <stdbool.h>
|
||||
#include "dfx.h"
|
||||
|
||||
/* #define DEBUG_DFX */
|
||||
#ifdef DEBUG_DFX
|
||||
#define debug(format...) NOTICE(format)
|
||||
#else
|
||||
#define debug(format, arg...)
|
||||
#endif
|
||||
|
||||
#define TSEN_CTRL0 0xf06f8084
|
||||
#define TSEN_CTRL0_START BIT(0)
|
||||
#define TSEN_CTRL0_RESET BIT(1)
|
||||
#define TSEN_CTRL0_ENABLE BIT(2)
|
||||
#define TSEN_CTRL0_AVG_BYPASS BIT(6)
|
||||
#define TSEN_CTRL0_CHAN_SHIFT 13
|
||||
#define TSEN_CTRL0_CHAN_MASK 0xF
|
||||
#define TSEN_CTRL0_OSR_SHIFT 24
|
||||
#define TSEN_CTRL0_OSR_MAX 0x3
|
||||
#define TSEN_CTRL0_MODE_SHIFT 30
|
||||
#define TSEN_CTRL0_MODE_EXTERNAL 0x2U
|
||||
#define TSEN_CTRL0_MODE_MASK 0x3U
|
||||
|
||||
#define TSEN_CTRL1 0xf06f8088
|
||||
#define TSEN_CTRL1_INT_EN BIT(25)
|
||||
#define TSEN_CTRL1_HYST_SHIFT 19
|
||||
#define TSEN_CTRL1_HYST_MASK (0x3 << TSEN_CTRL1_HYST_SHIFT)
|
||||
#define TSEN_CTRL1_THRESH_SHIFT 3
|
||||
#define TSEN_CTRL1_THRESH_MASK (0x3ff << TSEN_CTRL1_THRESH_SHIFT)
|
||||
|
||||
#define TSEN_STATUS 0xf06f808c
|
||||
#define TSEN_STATUS_VALID_OFFSET 16
|
||||
#define TSEN_STATUS_VALID_MASK (0x1 << TSEN_STATUS_VALID_OFFSET)
|
||||
#define TSEN_STATUS_TEMP_OUT_OFFSET 0
|
||||
#define TSEN_STATUS_TEMP_OUT_MASK (0x3FF << TSEN_STATUS_TEMP_OUT_OFFSET)
|
||||
|
||||
#define DFX_SERVER_IRQ_SUM_MASK_REG 0xf06f8104
|
||||
#define DFX_SERVER_IRQ_EN BIT(1)
|
||||
|
||||
#define DFX_IRQ_CAUSE_REG 0xf06f8108
|
||||
|
||||
#define DFX_IRQ_MASK_REG 0xf06f810c
|
||||
#define DFX_IRQ_TSEN_OVERHEAT_OFFSET BIT(22)
|
||||
|
||||
#define THERMAL_SEN_OUTPUT_MSB 512
|
||||
#define THERMAL_SEN_OUTPUT_COMP 1024
|
||||
|
||||
#define COEF_M 423
|
||||
#define COEF_B -150000LL
|
||||
|
||||
static void armada_ap806_thermal_read(u_register_t *temp)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = mmio_read_32(TSEN_STATUS);
|
||||
|
||||
reg = ((reg & TSEN_STATUS_TEMP_OUT_MASK) >>
|
||||
TSEN_STATUS_TEMP_OUT_OFFSET);
|
||||
|
||||
/*
|
||||
* TSEN output format is signed as a 2s complement number
|
||||
* ranging from-512 to +511. when MSB is set, need to
|
||||
* calculate the complement number
|
||||
*/
|
||||
if (reg >= THERMAL_SEN_OUTPUT_MSB)
|
||||
reg -= THERMAL_SEN_OUTPUT_COMP;
|
||||
|
||||
*temp = ((COEF_M * ((signed int)reg)) - COEF_B);
|
||||
}
|
||||
|
||||
static void armada_ap806_thermal_irq(void)
|
||||
{
|
||||
/* Dummy read, register ROC */
|
||||
mmio_read_32(DFX_IRQ_CAUSE_REG);
|
||||
}
|
||||
|
||||
static void armada_ap806_thermal_overheat_irq_init(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* Clear DFX temperature IRQ cause */
|
||||
reg = mmio_read_32(DFX_IRQ_CAUSE_REG);
|
||||
|
||||
/* Enable DFX Temperature IRQ */
|
||||
reg = mmio_read_32(DFX_IRQ_MASK_REG);
|
||||
reg |= DFX_IRQ_TSEN_OVERHEAT_OFFSET;
|
||||
mmio_write_32(DFX_IRQ_MASK_REG, reg);
|
||||
|
||||
/* Enable DFX server IRQ */
|
||||
reg = mmio_read_32(DFX_SERVER_IRQ_SUM_MASK_REG);
|
||||
reg |= DFX_SERVER_IRQ_EN;
|
||||
mmio_write_32(DFX_SERVER_IRQ_SUM_MASK_REG, reg);
|
||||
|
||||
/* Enable overheat interrupt */
|
||||
reg = mmio_read_32(TSEN_CTRL1);
|
||||
reg |= TSEN_CTRL1_INT_EN;
|
||||
mmio_write_32(TSEN_CTRL1, reg);
|
||||
}
|
||||
|
||||
static unsigned int armada_mc_to_reg_temp(unsigned int temp_mc)
|
||||
{
|
||||
unsigned int sample;
|
||||
|
||||
sample = (temp_mc + COEF_B) / COEF_M;
|
||||
|
||||
return sample & 0x3ff;
|
||||
}
|
||||
|
||||
/*
|
||||
* The documentation states:
|
||||
* high/low watermark = threshold +/- 0.4761 * 2^(hysteresis + 2)
|
||||
* which is the mathematical derivation for:
|
||||
* 0x0 <=> 1.9°C, 0x1 <=> 3.8°C, 0x2 <=> 7.6°C, 0x3 <=> 15.2°C
|
||||
*/
|
||||
static unsigned int hyst_levels_mc[] = {1900, 3800, 7600, 15200};
|
||||
|
||||
static unsigned int armada_mc_to_reg_hyst(int hyst_mc)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We will always take the smallest possible hysteresis to avoid risking
|
||||
* the hardware integrity by enlarging the threshold by +8°C in the
|
||||
* worst case.
|
||||
*/
|
||||
for (i = ARRAY_SIZE(hyst_levels_mc) - 1; i > 0; i--)
|
||||
if (hyst_mc >= hyst_levels_mc[i])
|
||||
break;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void armada_ap806_thermal_threshold(int thresh_mc, int hyst_mc)
|
||||
{
|
||||
uint32_t ctrl1;
|
||||
unsigned int threshold = armada_mc_to_reg_temp(thresh_mc);
|
||||
unsigned int hysteresis = armada_mc_to_reg_hyst(hyst_mc);
|
||||
|
||||
ctrl1 = mmio_read_32(TSEN_CTRL1);
|
||||
/* Set Threshold */
|
||||
if (thresh_mc >= 0) {
|
||||
ctrl1 &= ~(TSEN_CTRL1_THRESH_MASK);
|
||||
ctrl1 |= threshold << TSEN_CTRL1_THRESH_SHIFT;
|
||||
}
|
||||
|
||||
/* Set Hysteresis */
|
||||
if (hyst_mc >= 0) {
|
||||
ctrl1 &= ~(TSEN_CTRL1_HYST_MASK);
|
||||
ctrl1 |= hysteresis << TSEN_CTRL1_HYST_SHIFT;
|
||||
}
|
||||
|
||||
mmio_write_32(TSEN_CTRL1, ctrl1);
|
||||
}
|
||||
|
||||
static void armada_select_channel(int channel)
|
||||
{
|
||||
uint32_t ctrl0;
|
||||
|
||||
/* Stop the measurements */
|
||||
ctrl0 = mmio_read_32(TSEN_CTRL0);
|
||||
ctrl0 &= ~TSEN_CTRL0_START;
|
||||
mmio_write_32(TSEN_CTRL0, ctrl0);
|
||||
|
||||
/* Reset the mode, internal sensor will be automatically selected */
|
||||
ctrl0 &= ~(TSEN_CTRL0_MODE_MASK << TSEN_CTRL0_MODE_SHIFT);
|
||||
|
||||
/* Other channels are external and should be selected accordingly */
|
||||
if (channel) {
|
||||
/* Change the mode to external */
|
||||
ctrl0 |= TSEN_CTRL0_MODE_EXTERNAL <<
|
||||
TSEN_CTRL0_MODE_SHIFT;
|
||||
/* Select the sensor */
|
||||
ctrl0 &= ~(TSEN_CTRL0_CHAN_MASK << TSEN_CTRL0_CHAN_SHIFT);
|
||||
ctrl0 |= (channel - 1) << TSEN_CTRL0_CHAN_SHIFT;
|
||||
}
|
||||
|
||||
/* Actually set the mode/channel */
|
||||
mmio_write_32(TSEN_CTRL0, ctrl0);
|
||||
|
||||
/* Re-start the measurements */
|
||||
ctrl0 |= TSEN_CTRL0_START;
|
||||
mmio_write_32(TSEN_CTRL0, ctrl0);
|
||||
}
|
||||
|
||||
static void armada_ap806_thermal_init(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = mmio_read_32(TSEN_CTRL0);
|
||||
reg &= ~TSEN_CTRL0_RESET;
|
||||
reg |= TSEN_CTRL0_START | TSEN_CTRL0_ENABLE;
|
||||
|
||||
/* Sample every ~2ms */
|
||||
reg |= TSEN_CTRL0_OSR_MAX << TSEN_CTRL0_OSR_SHIFT;
|
||||
|
||||
/* Enable average (2 samples by default) */
|
||||
reg &= ~TSEN_CTRL0_AVG_BYPASS;
|
||||
|
||||
mmio_write_32(TSEN_CTRL0, reg);
|
||||
|
||||
debug("thermal: Initialization done\n");
|
||||
}
|
||||
|
||||
static void armada_is_valid(u_register_t *read)
|
||||
{
|
||||
*read = (mmio_read_32(TSEN_STATUS) & TSEN_STATUS_VALID_MASK);
|
||||
}
|
||||
|
||||
int mvebu_dfx_thermal_handle(u_register_t func, u_register_t *read,
|
||||
u_register_t x2, u_register_t x3)
|
||||
{
|
||||
debug_enter();
|
||||
|
||||
switch (func) {
|
||||
case MV_SIP_DFX_THERMAL_INIT:
|
||||
armada_ap806_thermal_init();
|
||||
break;
|
||||
case MV_SIP_DFX_THERMAL_READ:
|
||||
armada_ap806_thermal_read(read);
|
||||
break;
|
||||
case MV_SIP_DFX_THERMAL_IRQ:
|
||||
armada_ap806_thermal_irq();
|
||||
break;
|
||||
case MV_SIP_DFX_THERMAL_THRESH:
|
||||
armada_ap806_thermal_threshold(x2, x3);
|
||||
armada_ap806_thermal_overheat_irq_init();
|
||||
break;
|
||||
case MV_SIP_DFX_THERMAL_IS_VALID:
|
||||
armada_is_valid(read);
|
||||
break;
|
||||
case MV_SIP_DFX_THERMAL_SEL_CHANNEL:
|
||||
armada_select_channel(x2);
|
||||
break;
|
||||
default:
|
||||
ERROR("unsupported dfx func\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Marvell International Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* https://spdx.org/licenses
|
||||
*/
|
||||
|
||||
/* DFX sub-FID */
|
||||
#define MV_SIP_DFX_THERMAL_INIT 1
|
||||
#define MV_SIP_DFX_THERMAL_READ 2
|
||||
#define MV_SIP_DFX_THERMAL_IS_VALID 3
|
||||
#define MV_SIP_DFX_THERMAL_IRQ 4
|
||||
#define MV_SIP_DFX_THERMAL_THRESH 5
|
||||
#define MV_SIP_DFX_THERMAL_SEL_CHANNEL 6
|
||||
|
||||
#define MV_SIP_DFX_SREAD 20
|
||||
#define MV_SIP_DFX_SWRITE 21
|
||||
|
||||
int mvebu_dfx_thermal_handle(u_register_t func, u_register_t *read,
|
||||
u_register_t x2, u_register_t x3);
|
||||
int mvebu_dfx_misc_handle(u_register_t func, u_register_t *read,
|
||||
u_register_t addr, u_register_t val);
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Marvell International Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* https://spdx.org/licenses
|
||||
*/
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
#include "dfx.h"
|
||||
#include <mvebu_def.h>
|
||||
#include <mvebu.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* #define DEBUG_DFX */
|
||||
#ifdef DEBUG_DFX
|
||||
#define debug(format...) NOTICE(format)
|
||||
#else
|
||||
#define debug(format, arg...)
|
||||
#endif
|
||||
|
||||
#define SAR_BASE (MVEBU_REGS_BASE + 0x6F8200)
|
||||
#define SAR_SIZE 0x4
|
||||
#define AP_DEV_ID_STATUS_REG (MVEBU_REGS_BASE + 0x6F8240)
|
||||
#define JTAG_DEV_ID_STATUS_REG (MVEBU_REGS_BASE + 0x6F8244)
|
||||
#define EFUSE_CTRL (MVEBU_REGS_BASE + 0x6F8008)
|
||||
#define EFUSE_LD_BASE (MVEBU_REGS_BASE + 0x6F8F00)
|
||||
#define EFUSE_LD_SIZE 0x1C
|
||||
#define EFUSE_HD_BASE (MVEBU_REGS_BASE + 0x6F9000)
|
||||
#define EFUSE_HD_SIZE 0x3F8
|
||||
|
||||
/* AP806 CPU DFS register mapping*/
|
||||
#define AP806_CA72MP2_0_PLL_CR_0_BASE (MVEBU_REGS_BASE + 0x6F8278)
|
||||
#define AP806_CA72MP2_0_PLL_CR_1_BASE (MVEBU_REGS_BASE + 0x6F8280)
|
||||
#define AP806_CA72MP2_0_PLL_CR_2_BASE (MVEBU_REGS_BASE + 0x6F8284)
|
||||
#define AP806_CA72MP2_0_PLL_SR_BASE (MVEBU_REGS_BASE + 0x6F8C94)
|
||||
|
||||
/* AP807 CPU DFS register mapping */
|
||||
#define AP807_DEVICE_GENERAL_CR_10_BASE (MVEBU_REGS_BASE + 0x6F8278)
|
||||
#define AP807_DEVICE_GENERAL_CR_11_BASE (MVEBU_REGS_BASE + 0x6F827C)
|
||||
#define AP807_DEVICE_GENERAL_STATUS_6_BASE (MVEBU_REGS_BASE + 0x6F8C98)
|
||||
|
||||
#ifdef MVEBU_SOC_AP807
|
||||
#define CLUSTER_OFFSET 0x8
|
||||
#define CLK_DIVIDER_REG AP807_DEVICE_GENERAL_CR_10_BASE
|
||||
#define CLK_FORCE_REG AP807_DEVICE_GENERAL_CR_11_BASE
|
||||
#define CLK_RATIO_REG AP807_DEVICE_GENERAL_CR_11_BASE
|
||||
#define CLK_RATIO_STATE_REG AP807_DEVICE_GENERAL_STATUS_6_BASE
|
||||
#else
|
||||
#define CLUSTER_OFFSET 0x14
|
||||
#define CLK_DIVIDER_REG AP806_CA72MP2_0_PLL_CR_0_BASE
|
||||
#define CLK_FORCE_REG AP806_CA72MP2_0_PLL_CR_1_BASE
|
||||
#define CLK_RATIO_REG AP806_CA72MP2_0_PLL_CR_2_BASE
|
||||
#define CLK_RATIO_STATE_REG AP806_CA72MP2_0_PLL_SR_BASE
|
||||
#endif /* MVEBU_SOC_AP807 */
|
||||
|
||||
static _Bool is_valid(u_register_t addr)
|
||||
{
|
||||
switch (addr) {
|
||||
case AP_DEV_ID_STATUS_REG:
|
||||
case JTAG_DEV_ID_STATUS_REG:
|
||||
case SAR_BASE ... (SAR_BASE + SAR_SIZE):
|
||||
case EFUSE_LD_BASE ... (EFUSE_LD_BASE + EFUSE_LD_SIZE):
|
||||
case EFUSE_HD_BASE ... (EFUSE_HD_BASE + EFUSE_HD_SIZE):
|
||||
case EFUSE_CTRL:
|
||||
/* cpu-clk related registers */
|
||||
case CLK_DIVIDER_REG:
|
||||
case CLK_DIVIDER_REG + CLUSTER_OFFSET:
|
||||
case CLK_FORCE_REG:
|
||||
case CLK_FORCE_REG + CLUSTER_OFFSET:
|
||||
#ifndef MVEBU_SOC_AP807
|
||||
case CLK_RATIO_REG:
|
||||
case CLK_RATIO_REG + CLUSTER_OFFSET:
|
||||
#endif
|
||||
case CLK_RATIO_STATE_REG:
|
||||
case CLK_RATIO_STATE_REG + CLUSTER_OFFSET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int armada_dfx_sread(u_register_t *read, u_register_t addr)
|
||||
{
|
||||
if (!is_valid(addr))
|
||||
return -EINVAL;
|
||||
|
||||
*read = mmio_read_32(addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada_dfx_swrite(u_register_t addr, u_register_t val)
|
||||
{
|
||||
if (!is_valid(addr))
|
||||
return -EINVAL;
|
||||
|
||||
mmio_write_32(addr, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mvebu_dfx_misc_handle(u_register_t func, u_register_t *read,
|
||||
u_register_t addr, u_register_t val)
|
||||
{
|
||||
debug_enter();
|
||||
|
||||
debug("func %ld, addr 0x%lx, val 0x%lx\n", func, addr, val);
|
||||
|
||||
switch (func) {
|
||||
case MV_SIP_DFX_SREAD:
|
||||
return armada_dfx_sread(read, addr);
|
||||
case MV_SIP_DFX_SWRITE:
|
||||
return armada_dfx_swrite(addr, val);
|
||||
default:
|
||||
ERROR("unsupported dfx misc sub-func\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user