In production hardware the calibration values used to convert register values to temperatures can be read from hardware. While pre-production hardware still depends on pseudo values hard-coded in the driver. Add support for reading out calibration values from hardware if it's fused. The presence of fused calibration is indicated in the THSCP register. Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@xxxxxxxxxxxx> --- * Changes since RFT - Keep thcodes array static. --- drivers/thermal/rcar_gen3_thermal.c | 94 +++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 7d7e6ebe837a83af..897b625e1b498f05 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -34,6 +34,10 @@ #define REG_GEN3_THCODE1 0x50 #define REG_GEN3_THCODE2 0x54 #define REG_GEN3_THCODE3 0x58 +#define REG_GEN3_PTAT1 0x5c +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define REG_GEN3_THSCP 0x68 /* IRQ{STR,MSK,EN} bits */ #define IRQ_TEMP1 BIT(0) @@ -55,6 +59,9 @@ #define THCTR_PONM BIT(6) #define THCTR_THSST BIT(0) +/* THSCP bits */ +#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14)) + #define CTEMP_MASK 0xFFF #define MCELSIUS(temp) ((temp) * 1000) @@ -245,6 +252,64 @@ static const struct soc_device_attribute r8a7795es1[] = { { /* sentinel */ } }; +static bool rcar_gen3_thermal_update_fuses(struct rcar_gen3_thermal_priv *priv) +{ + unsigned int i; + u32 thscp; + + /* Default THCODE values in case FUSEs are not set. */ + static const int thcodes[TSC_MAX_NUM][3] = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, + { 3415, 2694, 2195 }, + { 3356, 2724, 2244 }, + }; + + /* If fuses are not set, fallback to pseudo values. */ + thscp = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_THSCP); + if ((thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) { + priv->ptat[0] = 2631; + priv->ptat[1] = 1509; + priv->ptat[2] = 435; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; + + tsc->thcode[0] = thcodes[i][0]; + tsc->thcode[1] = thcodes[i][1]; + tsc->thcode[2] = thcodes[i][2]; + } + + return false; + } + + /* + * Set the pseudo calibration points with fused values. + * PTAT is shared between all TSCs but only fused for the first + * TSC while THCODEs are fused for each TSC. + */ + priv->ptat[0] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT1) & + GEN3_FUSE_MASK; + priv->ptat[1] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT2) & + GEN3_FUSE_MASK; + priv->ptat[2] = rcar_gen3_thermal_read(priv->tscs[0], REG_GEN3_PTAT3) & + GEN3_FUSE_MASK; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; + + tsc->thcode[0] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE1) & + GEN3_FUSE_MASK; + tsc->thcode[1] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE2) & + GEN3_FUSE_MASK; + tsc->thcode[2] = rcar_gen3_thermal_read(tsc, REG_GEN3_THCODE3) & + GEN3_FUSE_MASK; + } + + return true; +} + static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc) { rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR); @@ -393,16 +458,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) unsigned int i; int ret; - /* Default THCODE values in case FUSEs are not set. */ - /* TODO: Read values from hardware on supported platforms */ - static const int thcodes[TSC_MAX_NUM][3] = { - { 3397, 2800, 2221 }, - { 3393, 2795, 2216 }, - { 3389, 2805, 2237 }, - { 3415, 2694, 2195 }, - { 3356, 2724, 2244 }, - }; - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -411,10 +466,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (soc_device_match(r8a7795es1)) priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; - priv->ptat[0] = 2631; - priv->ptat[1] = 1509; - priv->ptat[2] = 435; - platform_set_drvdata(pdev, priv); if (rcar_gen3_thermal_request_irqs(priv, pdev)) @@ -442,11 +493,16 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) goto error_unregister; } - tsc->thcode[0] = thcodes[i][0]; - tsc->thcode[1] = thcodes[i][1]; - tsc->thcode[2] = thcodes[i][2]; - priv->tscs[i] = tsc; + } + + priv->num_tscs = i; + + if (rcar_gen3_thermal_update_fuses(priv)) + dev_info(dev, "Using fused calibration values\n"); + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i]; zone = devm_thermal_zone_of_sensor_register(dev, i, tsc, &rcar_gen3_tz_of_ops); @@ -476,8 +532,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) dev_info(dev, "TSC%u: Loaded %d trip points\n", i, ret); } - priv->num_tscs = i; - if (!priv->num_tscs) { ret = -ENODEV; goto error_unregister; -- 2.33.0