aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap4_trim_quirks.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/omap4_trim_quirks.c')
-rw-r--r--arch/arm/mach-omap2/omap4_trim_quirks.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/omap4_trim_quirks.c b/arch/arm/mach-omap2/omap4_trim_quirks.c
new file mode 100644
index 0000000..dd96726
--- /dev/null
+++ b/arch/arm/mach-omap2/omap4_trim_quirks.c
@@ -0,0 +1,180 @@
+/*
+ * OMAP LDO control and configuration
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/cpu.h>
+
+#include "control.h"
+#include "pm.h"
+#include <mach/ctrl_module_core_44xx.h>
+
+#define OMAP4_DPLL_MPU_TRIMMED_VAL_2P4 (0x1 << 18)
+#define OMAP4_DPLL_MPU_TRIMMED_VAL_3P0 (0x3 << 18)
+#define OMAP4_DPLL_MPU_TRIMMED_MASK (BIT(19) | BIT(18))
+/*
+ * Trim value has to be written to CONTROL_EFUSE_2 according to
+ * OMAP4430 errata i684 (version B)
+ * OMAP4430 units with ProdID[51:50]=11 are not affected
+ */
+#define OMAP4_LPDDR2_I684_FIX_VALUE 0x004E4000
+#define OMAP4_PROD_ID_I684_MASK 0x000C0000
+
+
+static bool bgap_trim_sw_overide;
+static bool dpll_trim_override;
+static bool ddr_io_trim_override;
+
+/**
+ * omap4_ldo_trim_configure() - Handle device trim variance
+ *
+ * Few of the silicon out of the fab come out without trim parameters
+ * efused in. These need some software support to allow the device to
+ * function normally. Handle these silicon quirks here.
+ */
+int omap4_ldo_trim_configure(void)
+{
+ u32 val;
+
+ /* if not trimmed, we set force overide, insted of efuse. */
+ if (bgap_trim_sw_overide) {
+ /* Fill in recommended values */
+ val = 0x0f << OMAP4_LDOSRAMCORE_ACTMODE_VSET_OUT_SHIFT;
+ val |= OMAP4_LDOSRAMCORE_ACTMODE_MUX_CTRL_MASK;
+ val |= 0x1 << OMAP4_LDOSRAMCORE_RETMODE_VSET_OUT_SHIFT;
+ val |= OMAP4_LDOSRAMCORE_RETMODE_MUX_CTRL_MASK;
+
+ omap_ctrl_writel(val,
+ OMAP4_CTRL_MODULE_CORE_LDOSRAM_MPU_VOLTAGE_CTRL);
+ omap_ctrl_writel(val,
+ OMAP4_CTRL_MODULE_CORE_LDOSRAM_CORE_VOLTAGE_CTRL);
+ omap_ctrl_writel(val,
+ OMAP4_CTRL_MODULE_CORE_LDOSRAM_IVA_VOLTAGE_CTRL);
+ }
+
+ /* For all trimmed and untrimmed write value as per recomendation */
+ val = 0x10 << OMAP4_AVDAC_TRIM_BYTE0_SHIFT;
+ val |= 0x01 << OMAP4_AVDAC_TRIM_BYTE1_SHIFT;
+ val |= 0x4d << OMAP4_AVDAC_TRIM_BYTE2_SHIFT;
+ val |= 0x1C << OMAP4_AVDAC_TRIM_BYTE3_SHIFT;
+ omap4_ctrl_pad_writel(val,
+ OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_1);
+
+ /* DDR I/O Trim override as per erratum i684 */
+ if (ddr_io_trim_override) {
+ omap4_ctrl_pad_writel(OMAP4_LPDDR2_I684_FIX_VALUE,
+ OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_EFUSE_2);
+ }
+
+ /* Required for DPLL_MPU to lock at 2.4 GHz */
+ if (dpll_trim_override)
+ omap_ctrl_writel(0x29, OMAP4_CTRL_MODULE_CORE_DPLL_NWELL_TRIM_0);
+
+ return 0;
+}
+
+/**
+ * omap4460_mpu_dpll_trim_override() - provide a selective s/w trim overide
+ */
+static __init void omap4460_mpu_dpll_trim_override(void)
+{
+ u32 val;
+
+ val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_DPLL_1) &
+ OMAP4_DPLL_MPU_TRIMMED_MASK;
+ switch (val) {
+ case OMAP4_DPLL_MPU_TRIMMED_VAL_3P0:
+ /* all ok.. */
+ break;
+ case OMAP4_DPLL_MPU_TRIMMED_VAL_2P4:
+ /* Cross check! */
+ if (omap4_has_mpu_1_5ghz()) {
+ WARN(1, "%s: OMAP is 1.5GHz capable, trimmed=1.2GHz!\n",
+ __func__);
+ }
+ break;
+ default:
+ WARN(1, "%s: UNKNOWN TRIM:0x%08x, using s/w override\n",
+ __func__, val);
+ /* fall through and use override */
+ case 0:
+ /*
+ * For PRE_RTP devices: Not trimmed, use s/w override!
+ * We only support unto 1.2GHz with s/w override,
+ * so just give a gentle warning if higher opp is attempted
+ */
+ dpll_trim_override = true;
+ /* Confirm */
+ if (omap4_has_mpu_1_5ghz()) {
+ pr_err("%s: OMAP is 1.5GHz capable, s/w trim=1.2GHz!\n",
+ __func__);
+ }
+ break;
+ }
+}
+
+static __init int omap4_ldo_trim_init(void)
+{
+ u32 bgap_trimmed = 0;
+
+ /* Applicable only for OMAP4 */
+ if (!cpu_is_omap44xx())
+ return 0;
+
+ /*
+ * Some ES2.2 efuse values for BGAP and SLDO trim
+ * are not programmed. For these units
+ * 1. we can set overide mode for SLDO trim,
+ * and program the max multiplication factor, to ensure
+ * high enough voltage on SLDO output.
+ * 2. trim VDAC value for TV output as per recomendation
+ */
+ if (omap_rev() >= CHIP_IS_OMAP4430ES2_2)
+ bgap_trimmed = omap_ctrl_readl(
+ OMAP4_CTRL_MODULE_CORE_STD_FUSE_OPP_BGAP);
+
+ bgap_trimmed &= OMAP4_STD_FUSE_OPP_BGAP_MASK_LSB;
+
+ /* if not trimmed, we set force overide, insted of efuse. */
+ if (!bgap_trimmed)
+ bgap_trim_sw_overide = true;
+
+ /* If not already trimmed, use s/w override */
+ if (cpu_is_omap446x())
+ omap4460_mpu_dpll_trim_override();
+
+ /*
+ * Errata i684 (revision B)
+ * Impacts all OMAP4430ESx.y trimmed and untrimmed excluding units
+ * with with ProdID[51:50]=11
+ * OMAP4460/70 are not impacted.
+ *
+ * ProdID:
+ * 51 50
+ * 0 0 Incorrect trim, SW WA needed.
+ * 0 1 Fixed test program issue of overlapping of LPDDR & SmartIO
+ * efuse fields, SW WA needed for LPDDR.
+ * 1 1 New LPDDR trim formula to compensate for vertical vs horizontal
+ * cell layout. No overwrite required.
+ */
+ if (cpu_is_omap443x()) {
+ u32 prod_id;
+
+ prod_id = omap_ctrl_readl(
+ OMAP4_CTRL_MODULE_CORE_STD_FUSE_PROD_ID_1);
+ prod_id &= OMAP4_PROD_ID_I684_MASK;
+ if (prod_id != OMAP4_PROD_ID_I684_MASK)
+ ddr_io_trim_override = true;
+ }
+
+ return omap4_ldo_trim_configure();
+}
+arch_initcall(omap4_ldo_trim_init);