mach-imx6q.c 5.8 KB
Newer Older
1
/*
2
 * Copyright 2011-2013 Freescale Semiconductor, Inc.
3 4 5 6 7 8 9 10 11 12
 * Copyright 2011 Linaro Ltd.
 *
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

13 14
#include <linux/clk.h>
#include <linux/clkdev.h>
15
#include <linux/cpu.h>
R
Robert Lee 已提交
16
#include <linux/export.h>
17
#include <linux/init.h>
18
#include <linux/io.h>
19
#include <linux/irq.h>
20
#include <linux/irqchip.h>
21
#include <linux/of.h>
22
#include <linux/of_address.h>
23 24
#include <linux/of_irq.h>
#include <linux/of_platform.h>
25
#include <linux/opp.h>
26
#include <linux/phy.h>
27
#include <linux/reboot.h>
28
#include <linux/regmap.h>
29
#include <linux/micrel_phy.h>
30
#include <linux/mfd/syscon.h>
31
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
32
#include <asm/mach/arch.h>
33
#include <asm/mach/map.h>
34
#include <asm/system_misc.h>
35

36
#include "common.h"
37
#include "cpuidle.h"
38
#include "hardware.h"
R
Robert Lee 已提交
39

40 41 42
/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
static int ksz9021rn_phy_fixup(struct phy_device *phydev)
{
43
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
44
		/* min rx data delay */
45 46 47
		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
			0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW);
		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000);
48

49
		/* max rx/tx clock delay, min rx/tx control delay */
50 51 52 53 54
		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
			0x8000 | MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0xf0f0);
		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
			MICREL_KSZ9021_RGMII_CLK_CTRL_PAD_SCEW);
55
	}
56 57 58 59

	return 0;
}

60
static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val)
61
{
62 63 64 65
	phy_write(dev, 0x0d, device);
	phy_write(dev, 0x0e, reg);
	phy_write(dev, 0x0d, (1 << 14) | device);
	phy_write(dev, 0x0e, val);
66 67
}

68
static int ksz9031rn_phy_fixup(struct phy_device *dev)
69
{
70 71 72 73 74 75 76 77 78
	/*
	 * min rx data delay, max rx/tx clock delay,
	 * min rx/tx control delay
	 */
	mmd_write_reg(dev, 2, 4, 0);
	mmd_write_reg(dev, 2, 5, 0);
	mmd_write_reg(dev, 2, 8, 0x003ff);

	return 0;
79 80
}

81
static int ar8031_phy_fixup(struct phy_device *dev)
82
{
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
	u16 val;

	/* To enable AR8031 output a 125MHz clk from CLK_25M */
	phy_write(dev, 0xd, 0x7);
	phy_write(dev, 0xe, 0x8016);
	phy_write(dev, 0xd, 0x4007);

	val = phy_read(dev, 0xe);
	val &= 0xffe3;
	val |= 0x18;
	phy_write(dev, 0xe, val);

	/* introduce tx clock delay */
	phy_write(dev, 0x1d, 0x5);
	val = phy_read(dev, 0x1e);
	val |= 0x0100;
	phy_write(dev, 0x1e, val);

	return 0;
102 103
}

104 105
#define PHY_ID_AR8031	0x004dd074

106
static void __init imx6q_enet_phy_init(void)
107
{
108
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
109
		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
110
				ksz9021rn_phy_fixup);
111 112
		phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
				ksz9031rn_phy_fixup);
113 114
		phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
				ar8031_phy_fixup);
115
	}
116 117
}

118 119 120 121 122 123
static void __init imx6q_1588_init(void)
{
	struct regmap *gpr;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
	if (!IS_ERR(gpr))
124 125 126
		regmap_update_bits(gpr, IOMUXC_GPR1,
				IMX6Q_GPR1_ENET_CLK_SEL_MASK,
				IMX6Q_GPR1_ENET_CLK_SEL_ANATOP);
127 128 129 130
	else
		pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n");

}
131

132 133
static void __init imx6q_init_machine(void)
{
134 135
	struct device *parent;

136
	imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
137
			      imx_get_soc_revision());
138

139 140
	mxc_arch_reset_init_dt();

141 142 143 144
	parent = imx_soc_device_init();
	if (parent == NULL)
		pr_warn("failed to initialize soc device\n");

145
	imx6q_enet_phy_init();
146

147
	of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
148

149
	imx_anatop_init();
150
	imx6q_pm_init();
151
	imx6q_1588_init();
152 153
}

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
#define OCOTP_CFG3			0x440
#define OCOTP_CFG3_SPEED_SHIFT		16
#define OCOTP_CFG3_SPEED_1P2GHZ		0x3

static void __init imx6q_opp_check_1p2ghz(struct device *cpu_dev)
{
	struct device_node *np;
	void __iomem *base;
	u32 val;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-ocotp");
	if (!np) {
		pr_warn("failed to find ocotp node\n");
		return;
	}

	base = of_iomap(np, 0);
	if (!base) {
		pr_warn("failed to map ocotp\n");
		goto put_node;
	}

	val = readl_relaxed(base + OCOTP_CFG3);
	val >>= OCOTP_CFG3_SPEED_SHIFT;
	if ((val & 0x3) != OCOTP_CFG3_SPEED_1P2GHZ)
		if (opp_disable(cpu_dev, 1200000000))
			pr_warn("failed to disable 1.2 GHz OPP\n");

put_node:
	of_node_put(np);
}

186
static void __init imx6q_opp_init(void)
187 188
{
	struct device_node *np;
189
	struct device *cpu_dev = get_cpu_device(0);
190

191 192 193 194
	if (!cpu_dev) {
		pr_warn("failed to get cpu0 device\n");
		return;
	}
195
	np = of_node_get(cpu_dev->of_node);
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	if (!np) {
		pr_warn("failed to find cpu0 node\n");
		return;
	}

	if (of_init_opp_table(cpu_dev)) {
		pr_warn("failed to init OPP table\n");
		goto put_node;
	}

	imx6q_opp_check_1p2ghz(cpu_dev);

put_node:
	of_node_put(np);
}

212
static struct platform_device imx6q_cpufreq_pdev = {
213 214 215
	.name = "imx6q-cpufreq",
};

R
Robert Lee 已提交
216 217
static void __init imx6q_init_late(void)
{
218 219 220 221
	/*
	 * WAIT mode is broken on TO 1.0 and 1.1, so there is no point
	 * to run cpuidle on them.
	 */
222
	if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1)
223
		imx6q_cpuidle_init();
224 225

	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
226
		imx6q_opp_init();
227 228
		platform_device_register(&imx6q_cpufreq_pdev);
	}
R
Robert Lee 已提交
229 230
}

231 232
static void __init imx6q_map_io(void)
{
233
	debug_ll_io_init();
234 235 236 237 238
	imx_scu_map_io();
}

static void __init imx6q_init_irq(void)
{
239
	imx_init_revision_from_anatop();
240
	imx_init_l2cache();
241 242
	imx_src_init();
	imx_gpc_init();
243
	irqchip_init();
244 245 246
}

static const char *imx6q_dt_compat[] __initdata = {
S
Shawn Guo 已提交
247
	"fsl,imx6dl",
248
	"fsl,imx6q",
249 250 251
	NULL,
};

S
Shawn Guo 已提交
252
DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
253
	.smp		= smp_ops(imx_smp_ops),
254 255 256
	.map_io		= imx6q_map_io,
	.init_irq	= imx6q_init_irq,
	.init_machine	= imx6q_init_machine,
R
Robert Lee 已提交
257
	.init_late      = imx6q_init_late,
258
	.dt_compat	= imx6q_dt_compat,
259
	.restart	= mxc_restart,
260
MACHINE_END