18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  arch/arm/mach-vt8500/vt8500.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/pm.h>
108c2ecf20Sopenharmony_ci#include <linux/reboot.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
138c2ecf20Sopenharmony_ci#include <asm/mach/arch.h>
148c2ecf20Sopenharmony_ci#include <asm/mach/time.h>
158c2ecf20Sopenharmony_ci#include <asm/mach/map.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/of.h>
188c2ecf20Sopenharmony_ci#include <linux/of_address.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define LEGACY_GPIO_BASE	0xD8110000
228c2ecf20Sopenharmony_ci#define LEGACY_PMC_BASE		0xD8130000
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Registers in GPIO Controller */
258c2ecf20Sopenharmony_ci#define VT8500_GPIO_MUX_REG	0x200
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* Registers in Power Management Controller */
288c2ecf20Sopenharmony_ci#define VT8500_HCR_REG		0x12
298c2ecf20Sopenharmony_ci#define VT8500_PMSR_REG		0x60
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void __iomem *pmc_base;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void vt8500_restart(enum reboot_mode mode, const char *cmd)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	if (pmc_base)
368c2ecf20Sopenharmony_ci		writel(1, pmc_base + VT8500_PMSR_REG);
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic struct map_desc vt8500_io_desc[] __initdata = {
408c2ecf20Sopenharmony_ci	/* SoC MMIO registers */
418c2ecf20Sopenharmony_ci	[0] = {
428c2ecf20Sopenharmony_ci		.virtual	= 0xf8000000,
438c2ecf20Sopenharmony_ci		.pfn		= __phys_to_pfn(0xd8000000),
448c2ecf20Sopenharmony_ci		.length		= 0x00390000, /* max of all chip variants */
458c2ecf20Sopenharmony_ci		.type		= MT_DEVICE
468c2ecf20Sopenharmony_ci	},
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void __init vt8500_map_io(void)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc));
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void vt8500_power_off(void)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	local_irq_disable();
578c2ecf20Sopenharmony_ci	writew(5, pmc_base + VT8500_HCR_REG);
588c2ecf20Sopenharmony_ci	asm("mcr p15, 0, %0, c7, c0, 4" : : "r" (0));
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic void __init vt8500_init(void)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct device_node *np;
648c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_VT8500) || defined(CONFIG_FB_WM8505)
658c2ecf20Sopenharmony_ci	struct device_node *fb;
668c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
678c2ecf20Sopenharmony_ci#endif
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_VT8500
708c2ecf20Sopenharmony_ci	fb = of_find_compatible_node(NULL, NULL, "via,vt8500-fb");
718c2ecf20Sopenharmony_ci	if (fb) {
728c2ecf20Sopenharmony_ci		np = of_find_compatible_node(NULL, NULL, "via,vt8500-gpio");
738c2ecf20Sopenharmony_ci		if (np) {
748c2ecf20Sopenharmony_ci			gpio_base = of_iomap(np, 0);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci			if (!gpio_base)
778c2ecf20Sopenharmony_ci				pr_err("%s: of_iomap(gpio_mux) failed\n",
788c2ecf20Sopenharmony_ci								__func__);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci			of_node_put(np);
818c2ecf20Sopenharmony_ci		} else {
828c2ecf20Sopenharmony_ci			gpio_base = ioremap(LEGACY_GPIO_BASE, 0x1000);
838c2ecf20Sopenharmony_ci			if (!gpio_base)
848c2ecf20Sopenharmony_ci				pr_err("%s: ioremap(legacy_gpio_mux) failed\n",
858c2ecf20Sopenharmony_ci								__func__);
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci		if (gpio_base) {
888c2ecf20Sopenharmony_ci			writel(readl(gpio_base + VT8500_GPIO_MUX_REG) | 1,
898c2ecf20Sopenharmony_ci				gpio_base + VT8500_GPIO_MUX_REG);
908c2ecf20Sopenharmony_ci			iounmap(gpio_base);
918c2ecf20Sopenharmony_ci		} else
928c2ecf20Sopenharmony_ci			pr_err("%s: Could not remap GPIO mux\n", __func__);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		of_node_put(fb);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci#endif
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_WM8505
998c2ecf20Sopenharmony_ci	fb = of_find_compatible_node(NULL, NULL, "wm,wm8505-fb");
1008c2ecf20Sopenharmony_ci	if (fb) {
1018c2ecf20Sopenharmony_ci		np = of_find_compatible_node(NULL, NULL, "wm,wm8505-gpio");
1028c2ecf20Sopenharmony_ci		if (!np)
1038c2ecf20Sopenharmony_ci			np = of_find_compatible_node(NULL, NULL,
1048c2ecf20Sopenharmony_ci							"wm,wm8650-gpio");
1058c2ecf20Sopenharmony_ci		if (np) {
1068c2ecf20Sopenharmony_ci			gpio_base = of_iomap(np, 0);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci			if (!gpio_base)
1098c2ecf20Sopenharmony_ci				pr_err("%s: of_iomap(gpio_mux) failed\n",
1108c2ecf20Sopenharmony_ci								__func__);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci			of_node_put(np);
1138c2ecf20Sopenharmony_ci		} else {
1148c2ecf20Sopenharmony_ci			gpio_base = ioremap(LEGACY_GPIO_BASE, 0x1000);
1158c2ecf20Sopenharmony_ci			if (!gpio_base)
1168c2ecf20Sopenharmony_ci				pr_err("%s: ioremap(legacy_gpio_mux) failed\n",
1178c2ecf20Sopenharmony_ci								__func__);
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci		if (gpio_base) {
1208c2ecf20Sopenharmony_ci			writel(readl(gpio_base + VT8500_GPIO_MUX_REG) |
1218c2ecf20Sopenharmony_ci				0x80000000, gpio_base + VT8500_GPIO_MUX_REG);
1228c2ecf20Sopenharmony_ci			iounmap(gpio_base);
1238c2ecf20Sopenharmony_ci		} else
1248c2ecf20Sopenharmony_ci			pr_err("%s: Could not remap GPIO mux\n", __func__);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		of_node_put(fb);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci#endif
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "via,vt8500-pmc");
1318c2ecf20Sopenharmony_ci	if (np) {
1328c2ecf20Sopenharmony_ci		pmc_base = of_iomap(np, 0);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		if (!pmc_base)
1358c2ecf20Sopenharmony_ci			pr_err("%s:of_iomap(pmc) failed\n", __func__);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		of_node_put(np);
1388c2ecf20Sopenharmony_ci	} else {
1398c2ecf20Sopenharmony_ci		pmc_base = ioremap(LEGACY_PMC_BASE, 0x1000);
1408c2ecf20Sopenharmony_ci		if (!pmc_base)
1418c2ecf20Sopenharmony_ci			pr_err("%s:ioremap(power_off) failed\n", __func__);
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci	if (pmc_base)
1448c2ecf20Sopenharmony_ci		pm_power_off = &vt8500_power_off;
1458c2ecf20Sopenharmony_ci	else
1468c2ecf20Sopenharmony_ci		pr_err("%s: PMC Hibernation register could not be remapped, not enabling power off!\n", __func__);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic const char * const vt8500_dt_compat[] = {
1508c2ecf20Sopenharmony_ci	"via,vt8500",
1518c2ecf20Sopenharmony_ci	"wm,wm8650",
1528c2ecf20Sopenharmony_ci	"wm,wm8505",
1538c2ecf20Sopenharmony_ci	"wm,wm8750",
1548c2ecf20Sopenharmony_ci	"wm,wm8850",
1558c2ecf20Sopenharmony_ci	NULL
1568c2ecf20Sopenharmony_ci};
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ciDT_MACHINE_START(WMT_DT, "VIA/Wondermedia SoC (Device Tree Support)")
1598c2ecf20Sopenharmony_ci	.dt_compat	= vt8500_dt_compat,
1608c2ecf20Sopenharmony_ci	.map_io		= vt8500_map_io,
1618c2ecf20Sopenharmony_ci	.init_machine	= vt8500_init,
1628c2ecf20Sopenharmony_ci	.restart	= vt8500_restart,
1638c2ecf20Sopenharmony_ciMACHINE_END
1648c2ecf20Sopenharmony_ci
165