Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
0004  * Copyright 2017-2018 NXP.
0005  */
0006 
0007 #include <linux/err.h>
0008 #include <linux/io.h>
0009 #include <linux/of.h>
0010 #include <linux/of_address.h>
0011 #include <linux/mfd/syscon.h>
0012 #include <linux/regmap.h>
0013 #include "common.h"
0014 #include "hardware.h"
0015 
0016 #define REG_SET     0x4
0017 #define REG_CLR     0x8
0018 
0019 #define ANADIG_REG_2P5      0x130
0020 #define ANADIG_REG_CORE     0x140
0021 #define ANADIG_ANA_MISC0    0x150
0022 #define ANADIG_DIGPROG      0x260
0023 #define ANADIG_DIGPROG_IMX6SL   0x280
0024 #define ANADIG_DIGPROG_IMX7D    0x800
0025 
0026 #define SRC_SBMR2       0x1c
0027 
0028 #define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG    0x40000
0029 #define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN   0x8
0030 #define BM_ANADIG_REG_CORE_FET_ODRIVE       0x20000000
0031 #define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG    0x1000
0032 /* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
0033 #define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS    0x2000
0034 
0035 static struct regmap *anatop;
0036 
0037 static void imx_anatop_enable_weak2p5(bool enable)
0038 {
0039     u32 reg, val;
0040 
0041     regmap_read(anatop, ANADIG_ANA_MISC0, &val);
0042 
0043     /* can only be enabled when stop_mode_config is clear. */
0044     reg = ANADIG_REG_2P5;
0045     reg += (enable && (val & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) ?
0046         REG_SET : REG_CLR;
0047     regmap_write(anatop, reg, BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG);
0048 }
0049 
0050 static void imx_anatop_enable_fet_odrive(bool enable)
0051 {
0052     regmap_write(anatop, ANADIG_REG_CORE + (enable ? REG_SET : REG_CLR),
0053         BM_ANADIG_REG_CORE_FET_ODRIVE);
0054 }
0055 
0056 static inline void imx_anatop_enable_2p5_pulldown(bool enable)
0057 {
0058     regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
0059         BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
0060 }
0061 
0062 static inline void imx_anatop_disconnect_high_snvs(bool enable)
0063 {
0064     regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
0065         BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
0066 }
0067 
0068 void imx_anatop_pre_suspend(void)
0069 {
0070     if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
0071         imx_anatop_enable_2p5_pulldown(true);
0072     else
0073         imx_anatop_enable_weak2p5(true);
0074 
0075     imx_anatop_enable_fet_odrive(true);
0076 
0077     if (cpu_is_imx6sl())
0078         imx_anatop_disconnect_high_snvs(true);
0079 }
0080 
0081 void imx_anatop_post_resume(void)
0082 {
0083     if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
0084         imx_anatop_enable_2p5_pulldown(false);
0085     else
0086         imx_anatop_enable_weak2p5(false);
0087 
0088     imx_anatop_enable_fet_odrive(false);
0089 
0090     if (cpu_is_imx6sl())
0091         imx_anatop_disconnect_high_snvs(false);
0092 }
0093 
0094 void __init imx_init_revision_from_anatop(void)
0095 {
0096     struct device_node *np, *src_np;
0097     void __iomem *anatop_base;
0098     unsigned int revision;
0099     u32 digprog;
0100     u16 offset = ANADIG_DIGPROG;
0101     u8 major_part, minor_part;
0102 
0103     np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-anatop");
0104     anatop_base = of_iomap(np, 0);
0105     WARN_ON(!anatop_base);
0106     if (of_device_is_compatible(np, "fsl,imx6sl-anatop"))
0107         offset = ANADIG_DIGPROG_IMX6SL;
0108     if (of_device_is_compatible(np, "fsl,imx7d-anatop"))
0109         offset = ANADIG_DIGPROG_IMX7D;
0110     digprog = readl_relaxed(anatop_base + offset);
0111     iounmap(anatop_base);
0112 
0113     /*
0114      * On i.MX7D digprog value match linux version format, so
0115      * it needn't map again and we can use register value directly.
0116      */
0117     if (of_device_is_compatible(np, "fsl,imx7d-anatop")) {
0118         revision = digprog & 0xff;
0119     } else {
0120         /*
0121          * MAJOR: [15:8], the major silicon revison;
0122          * MINOR: [7: 0], the minor silicon revison;
0123          *
0124          * please refer to the i.MX RM for the detailed
0125          * silicon revison bit define.
0126          * format the major part and minor part to match the
0127          * linux kernel soc version format.
0128          */
0129         major_part = (digprog >> 8) & 0xf;
0130         minor_part = digprog & 0xf;
0131         revision = ((major_part + 1) << 4) | minor_part;
0132 
0133         if ((digprog >> 16) == MXC_CPU_IMX6ULL) {
0134             void __iomem *src_base;
0135             u32 sbmr2;
0136 
0137             src_np = of_find_compatible_node(NULL, NULL,
0138                              "fsl,imx6ul-src");
0139             src_base = of_iomap(src_np, 0);
0140             of_node_put(src_np);
0141             WARN_ON(!src_base);
0142             sbmr2 = readl_relaxed(src_base + SRC_SBMR2);
0143             iounmap(src_base);
0144 
0145             /* src_sbmr2 bit 6 is to identify if it is i.MX6ULZ */
0146             if (sbmr2 & (1 << 6)) {
0147                 digprog &= ~(0xff << 16);
0148                 digprog |= (MXC_CPU_IMX6ULZ << 16);
0149             }
0150         }
0151     }
0152     of_node_put(np);
0153 
0154     mxc_set_cpu_type(digprog >> 16 & 0xff);
0155     imx_set_soc_revision(revision);
0156 }
0157 
0158 void __init imx_anatop_init(void)
0159 {
0160     anatop = syscon_regmap_lookup_by_compatible("fsl,imx6q-anatop");
0161     if (IS_ERR(anatop))
0162         pr_err("%s: failed to find imx6q-anatop regmap!\n", __func__);
0163 }