diff --git a/src/soc/mediatek/common/include/soc/mt6363_sdmadc.h b/src/soc/mediatek/common/include/soc/mt6363_sdmadc.h new file mode 100644 index 0000000000..ae990c9cb7 --- /dev/null +++ b/src/soc/mediatek/common/include/soc/mt6363_sdmadc.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __MT6363_SDMADC_H__ +#define __MT6363_SDMADC_H__ + +#include +#include + +enum { + PMIC_AUXADC_ADC_OUT_CH12_L_ADDR = 0x10d2, + MT6363_AUXADC_RQST1 = 0x1109, + PMIC_SDMADC_EXT_THR_SRC_SEL_ADDR = 0x11c4, +}; + +/* + * enum auxadc_channels - enumeration of auxadc channels + */ +enum auxadc_channel { + AUXADC_CHAN_VIN1, + AUXADC_CHAN_VIN2, + AUXADC_CHAN_VIN3, + AUXADC_CHAN_VIN4, + AUXADC_CHAN_VIN5, + AUXADC_CHAN_VIN6, + AUXADC_CHAN_VIN7, + AUXADC_CHAN_MAX, +}; + +/* + * enum sdmadc_pures - enumeration of sdmadc pull up resistor + */ +enum sdmadc_pures { + SDMADC_100K, + SDMADC_30K, + SDMADC_400K, + SDMADC_OPEN, +}; + +/** + * enum auxadc_val_type - enumeration of auxadc value's type + */ +enum auxadc_val_type { + AUXADC_VAL_PROCESSED, + AUXADC_VAL_RAW, +}; + +/** + * struct auxadc_chan_spec - specification of an auxadc channel + * @channel: What auxadc_channel is it. + * @hw_info: Hardware design level information + * @hw_info.ref_volt Reference voltage + * @hw_info.ratio: Resistor Ratio. + * If read operation is not provided, the processed + * value will be calculated as following: + * (raw value * ratio[0] * ref_volt) / ratio[1] + * @hw_info.max_time: Maximum wait time(us). + * @hw_info.min_time: Minimum wait time(us). + * @hw_info.poll_time: Wait time(us) between every polling during retry. + * @hw_info.enable_reg Register address of enable control. + * @hw_info.enable_mask Mask of enable control. + * @hw_info.ready_reg Register address of channel's ready status. + * @hw_info.ready_mask Mask of ready status. + * @hw_info.value_reg Register address of raw value. + * @hw_info.res Resolution of this channel (number of valid bits). + */ +struct auxadc_chan_spec { + int channel; + struct { + u32 ref_volt; + u32 ratio[2]; + u32 max_time; + u32 min_time; + u32 poll_time; + u32 enable_reg; + u32 enable_mask; + u32 ready_reg; + u32 ready_mask; + u32 value_reg; + u8 res; + } hw_info; + struct { + u32 set_reg; + u32 cmd; + } sdmadc_hw_info; +}; + +int mt6363_sdmadc_read(enum auxadc_channel channel, int *val, enum sdmadc_pures pures, + enum auxadc_val_type type); + +#endif /* __MT6363_SDMADC_H__ */ diff --git a/src/soc/mediatek/common/mt6363_sdmadc.c b/src/soc/mediatek/common/mt6363_sdmadc.c new file mode 100644 index 0000000000..eb4b9780a6 --- /dev/null +++ b/src/soc/mediatek/common/mt6363_sdmadc.c @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ + +/* + * These values are used by MediaTek internally. + * We can find these registers in "MT6363TP_PMIC_Design_Notice_for_MT8196G_V0.2" + * Chapter number: 2.15. + * The setting values are provided by MeidaTek designers. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ERR_INVALID_ARGS (-8) +#define ERR_TIMED_OUT (-13) + +#define AUXADC_RDY_BIT BIT(15) +/* 0.385us(2.89MHz) x 42T (SPL(100K=29T)+ADC_compare(12T)+sync(1T)) ~= 16us */ +#define AUXADC_AVG_TIME_US 16 +#define AUXADC_POLL_TIME_US 100 +#define AUXADC_TIMEOUT_US 32000 +#define VOLT_FULL 1840 + +#define EXT_THR_SEL_DEF_VALUE 0x80 +#define EXT_THR_PURES_SHIFT 3 + +#define SDMADC_CHAN_SPEC(src_sel) \ +{ \ + .hw_info = { \ + .ref_volt = VOLT_FULL, \ + .min_time = 128 * AUXADC_AVG_TIME_US, \ + .max_time = AUXADC_TIMEOUT_US, \ + .poll_time = AUXADC_POLL_TIME_US, \ + .ratio = { 1, 1 }, \ + .enable_reg = MT6363_AUXADC_RQST1, \ + .enable_mask = BIT(4), \ + .ready_reg = PMIC_AUXADC_ADC_OUT_CH12_L_ADDR, \ + .ready_mask = AUXADC_RDY_BIT, \ + .res = 15, \ + }, \ + .sdmadc_hw_info = { \ + .set_reg = PMIC_SDMADC_EXT_THR_SRC_SEL_ADDR, \ + .cmd = EXT_THR_SEL_DEF_VALUE | src_sel, \ + }, \ +} + +static const struct auxadc_chan_spec mt6363_sdmadc_chan_specs[] = { + [AUXADC_CHAN_VIN1] = SDMADC_CHAN_SPEC(1), + [AUXADC_CHAN_VIN2] = SDMADC_CHAN_SPEC(2), + [AUXADC_CHAN_VIN3] = SDMADC_CHAN_SPEC(3), + [AUXADC_CHAN_VIN4] = SDMADC_CHAN_SPEC(4), + [AUXADC_CHAN_VIN5] = SDMADC_CHAN_SPEC(5), + [AUXADC_CHAN_VIN6] = SDMADC_CHAN_SPEC(6), + [AUXADC_CHAN_VIN7] = SDMADC_CHAN_SPEC(7), +}; + +_Static_assert(ARRAY_SIZE(mt6363_sdmadc_chan_specs) == AUXADC_CHAN_MAX, + "Wrong array size for mt6363_sdmadc_chan_specs"); + +int mt6363_sdmadc_read(enum auxadc_channel channel, int *val, + enum sdmadc_pures pures, enum auxadc_val_type type) +{ + u8 wdata; + u32 regval; + u32 elapsed = 0; + const struct auxadc_chan_spec *chan; + + if (channel < AUXADC_CHAN_VIN1 || channel >= AUXADC_CHAN_MAX) { + printk(BIOS_ERR, "[%s] Invalid channel %d\n", __func__, channel); + return ERR_INVALID_ARGS; + } + + mt6363_init_pmif_arb(); + chan = &mt6363_sdmadc_chan_specs[channel]; + + wdata = chan->sdmadc_hw_info.cmd | (pures << EXT_THR_PURES_SHIFT); + mt6363_write8(chan->sdmadc_hw_info.set_reg, wdata); + + wdata = chan->hw_info.enable_mask; + mt6363_write8(chan->hw_info.enable_reg, wdata); + + udelay(chan->hw_info.min_time); + elapsed += chan->hw_info.min_time; + + while (1) { + regval = mt6363_read16(chan->hw_info.ready_reg); + if (regval & chan->hw_info.ready_mask) + break; + if (elapsed > chan->hw_info.max_time) { + printk(BIOS_ERR, "[%s] Auxadc read time out", __func__); + return ERR_TIMED_OUT; + } + udelay(chan->hw_info.poll_time); + elapsed += chan->hw_info.poll_time; + } + + regval &= (BIT(chan->hw_info.res) - 1); + switch (type) { + case AUXADC_VAL_RAW: + *val = regval; + break; + case AUXADC_VAL_PROCESSED: + *val = ((regval * chan->hw_info.ratio[0] * chan->hw_info.ref_volt) / + chan->hw_info.ratio[1]) >> chan->hw_info.res; + break; + } + return 0; +} diff --git a/src/soc/mediatek/mt8196/Makefile.mk b/src/soc/mediatek/mt8196/Makefile.mk index 7a950d24cb..2a01ee5582 100644 --- a/src/soc/mediatek/mt8196/Makefile.mk +++ b/src/soc/mediatek/mt8196/Makefile.mk @@ -45,6 +45,7 @@ ramstage-y += ../common/mcu.c ramstage-y += ../common/mmu_operations.c ../common/mmu_cmops.c ramstage-$(CONFIG_PCI) += ../common/pcie.c pcie.c ramstage-y += ../common/mt6363.c mt6363.c +ramstage-y += ../common/mt6363_sdmadc.c ramstage-y += soc.c ramstage-y += ../common/pmif_clk.c pmif_clk.c ramstage-y += ../common/pmif.c pmif_init.c