mach-imx6q.c 6.4 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>
16
#include <linux/delay.h>
R
Robert Lee 已提交
17
#include <linux/export.h>
18
#include <linux/init.h>
19
#include <linux/io.h>
20
#include <linux/irq.h>
21
#include <linux/irqchip.h>
22
#include <linux/of.h>
23
#include <linux/of_address.h>
24 25
#include <linux/of_irq.h>
#include <linux/of_platform.h>
26
#include <linux/opp.h>
27
#include <linux/phy.h>
28
#include <linux/reboot.h>
29
#include <linux/regmap.h>
30
#include <linux/micrel_phy.h>
31
#include <linux/mfd/syscon.h>
32
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
33
#include <asm/mach/arch.h>
34
#include <asm/mach/map.h>
35
#include <asm/system_misc.h>
36

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

41
static void imx6q_restart(enum reboot_mode mode, const char *cmd)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
{
	struct device_node *np;
	void __iomem *wdog_base;

	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-wdt");
	wdog_base = of_iomap(np, 0);
	if (!wdog_base)
		goto soft;

	imx_src_prepare_restart();

	/* enable wdog */
	writew_relaxed(1 << 2, wdog_base);
	/* write twice to ensure the request will not get ignored */
	writew_relaxed(1 << 2, wdog_base);

	/* wait for reset to assert ... */
	mdelay(500);

	pr_err("Watchdog reset failed to assert reset\n");

	/* delay to allow the serial port to show the message */
	mdelay(50);

soft:
	/* we'll take a jump through zero as a poor second */
	soft_restart(0);
}

71 72 73
/* For imx6q sabrelite board: set KSZ9021RN RGMII pad skew */
static int ksz9021rn_phy_fixup(struct phy_device *phydev)
{
74
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
75
		/* min rx data delay */
76 77 78
		phy_write(phydev, MICREL_KSZ9021_EXTREG_CTRL,
			0x8000 | MICREL_KSZ9021_RGMII_RX_DATA_PAD_SCEW);
		phy_write(phydev, MICREL_KSZ9021_EXTREG_DATA_WRITE, 0x0000);
79

80
		/* max rx/tx clock delay, min rx/tx control delay */
81 82 83 84 85
		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);
86
	}
87 88 89 90

	return 0;
}

91
static void mmd_write_reg(struct phy_device *dev, int device, int reg, int val)
92
{
93 94 95 96
	phy_write(dev, 0x0d, device);
	phy_write(dev, 0x0e, reg);
	phy_write(dev, 0x0d, (1 << 14) | device);
	phy_write(dev, 0x0e, val);
97 98
}

99
static int ksz9031rn_phy_fixup(struct phy_device *dev)
100
{
101 102 103 104 105 106 107 108 109
	/*
	 * 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;
110 111
}

112
static int ar8031_phy_fixup(struct phy_device *dev)
113
{
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	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;
133 134
}

135 136
#define PHY_ID_AR8031	0x004dd074

137
static void __init imx6q_enet_phy_init(void)
138
{
139
	if (IS_BUILTIN(CONFIG_PHYLIB)) {
140
		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
141
				ksz9021rn_phy_fixup);
142 143
		phy_register_fixup_for_uid(PHY_ID_KSZ9031, MICREL_PHY_ID_MASK,
				ksz9031rn_phy_fixup);
144 145
		phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
				ar8031_phy_fixup);
146
	}
147 148
}

149 150 151 152 153 154
static void __init imx6q_1588_init(void)
{
	struct regmap *gpr;

	gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
	if (!IS_ERR(gpr))
155 156 157
		regmap_update_bits(gpr, IOMUXC_GPR1,
				IMX6Q_GPR1_ENET_CLK_SEL_MASK,
				IMX6Q_GPR1_ENET_CLK_SEL_ANATOP);
158 159 160 161
	else
		pr_err("failed to find fsl,imx6q-iomux-gpr regmap\n");

}
162

163 164
static void __init imx6q_init_machine(void)
{
165
	imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
166
			      imx_get_soc_revision());
167

168
	imx6q_enet_phy_init();
169

170 171
	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);

172
	imx_anatop_init();
173
	imx6q_pm_init();
174
	imx6q_1588_init();
175 176
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
#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);
}

209
static void __init imx6q_opp_init(void)
210 211
{
	struct device_node *np;
212
	struct device *cpu_dev = get_cpu_device(0);
213

214 215 216 217
	if (!cpu_dev) {
		pr_warn("failed to get cpu0 device\n");
		return;
	}
218
	np = of_node_get(cpu_dev->of_node);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	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);
}

235
static struct platform_device imx6q_cpufreq_pdev = {
236 237 238
	.name = "imx6q-cpufreq",
};

R
Robert Lee 已提交
239 240
static void __init imx6q_init_late(void)
{
241 242 243 244
	/*
	 * WAIT mode is broken on TO 1.0 and 1.1, so there is no point
	 * to run cpuidle on them.
	 */
245
	if (imx_get_soc_revision() > IMX_CHIP_REVISION_1_1)
246
		imx6q_cpuidle_init();
247 248

	if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ)) {
249
		imx6q_opp_init();
250 251
		platform_device_register(&imx6q_cpufreq_pdev);
	}
R
Robert Lee 已提交
252 253
}

254 255
static void __init imx6q_map_io(void)
{
256
	debug_ll_io_init();
257 258 259 260 261
	imx_scu_map_io();
}

static void __init imx6q_init_irq(void)
{
262
	imx_init_revision_from_anatop();
263
	imx_init_l2cache();
264 265
	imx_src_init();
	imx_gpc_init();
266
	irqchip_init();
267 268 269
}

static const char *imx6q_dt_compat[] __initdata = {
S
Shawn Guo 已提交
270
	"fsl,imx6dl",
271
	"fsl,imx6q",
272 273 274
	NULL,
};

S
Shawn Guo 已提交
275
DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
276
	.smp		= smp_ops(imx_smp_ops),
277 278 279
	.map_io		= imx6q_map_io,
	.init_irq	= imx6q_init_irq,
	.init_machine	= imx6q_init_machine,
R
Robert Lee 已提交
280
	.init_late      = imx6q_init_late,
281
	.dt_compat	= imx6q_dt_compat,
282
	.restart	= imx6q_restart,
283
MACHINE_END