162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Keystone2 based boards and SOC related code.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2013 Texas Instruments, Inc.
662306a36Sopenharmony_ci *	Cyril Chemparathy <cyril@ti.com>
762306a36Sopenharmony_ci *	Santosh Shilimkar <santosh.shillimkar@ti.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/dma-map-ops.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1462306a36Sopenharmony_ci#include <linux/pm_clock.h>
1562306a36Sopenharmony_ci#include <linux/memblock.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/setup.h>
2062306a36Sopenharmony_ci#include <asm/mach/map.h>
2162306a36Sopenharmony_ci#include <asm/mach/arch.h>
2262306a36Sopenharmony_ci#include <asm/mach/time.h>
2362306a36Sopenharmony_ci#include <asm/page.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define KEYSTONE_LOW_PHYS_START		0x80000000ULL
2662306a36Sopenharmony_ci#define KEYSTONE_LOW_PHYS_SIZE		0x80000000ULL /* 2G */
2762306a36Sopenharmony_ci#define KEYSTONE_LOW_PHYS_END		(KEYSTONE_LOW_PHYS_START + \
2862306a36Sopenharmony_ci					 KEYSTONE_LOW_PHYS_SIZE - 1)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define KEYSTONE_HIGH_PHYS_START	0x800000000ULL
3162306a36Sopenharmony_ci#define KEYSTONE_HIGH_PHYS_SIZE		0x400000000ULL	/* 16G */
3262306a36Sopenharmony_ci#define KEYSTONE_HIGH_PHYS_END		(KEYSTONE_HIGH_PHYS_START + \
3362306a36Sopenharmony_ci					 KEYSTONE_HIGH_PHYS_SIZE - 1)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic struct dev_pm_domain keystone_pm_domain = {
3662306a36Sopenharmony_ci	.ops = {
3762306a36Sopenharmony_ci		USE_PM_CLK_RUNTIME_OPS
3862306a36Sopenharmony_ci		USE_PLATFORM_PM_SLEEP_OPS
3962306a36Sopenharmony_ci	},
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic struct pm_clk_notifier_block platform_domain_notifier = {
4362306a36Sopenharmony_ci	.pm_domain = &keystone_pm_domain,
4462306a36Sopenharmony_ci	.con_ids = { NULL },
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct of_device_id of_keystone_table[] = {
4862306a36Sopenharmony_ci	{.compatible = "ti,k2hk"},
4962306a36Sopenharmony_ci	{.compatible = "ti,k2e"},
5062306a36Sopenharmony_ci	{.compatible = "ti,k2l"},
5162306a36Sopenharmony_ci	{ /* end of list */ },
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int __init keystone_pm_runtime_init(void)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct device_node *np;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	np = of_find_matching_node(NULL, of_keystone_table);
5962306a36Sopenharmony_ci	if (!np)
6062306a36Sopenharmony_ci		return 0;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	pm_clk_add_notifier(&platform_bus_type, &platform_domain_notifier);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return 0;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
6862306a36Sopenharmony_cistatic int keystone_platform_notifier(struct notifier_block *nb,
6962306a36Sopenharmony_ci				      unsigned long event, void *data)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	struct device *dev = data;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (event != BUS_NOTIFY_ADD_DEVICE)
7462306a36Sopenharmony_ci		return NOTIFY_DONE;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (!dev)
7762306a36Sopenharmony_ci		return NOTIFY_BAD;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (!dev->of_node) {
8062306a36Sopenharmony_ci		int ret = dma_direct_set_offset(dev, KEYSTONE_HIGH_PHYS_START,
8162306a36Sopenharmony_ci						KEYSTONE_LOW_PHYS_START,
8262306a36Sopenharmony_ci						KEYSTONE_HIGH_PHYS_SIZE);
8362306a36Sopenharmony_ci		dev_err(dev, "set dma_offset%08llx%s\n",
8462306a36Sopenharmony_ci			KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START,
8562306a36Sopenharmony_ci			ret ? " failed" : "");
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci	return NOTIFY_OK;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic struct notifier_block platform_nb = {
9162306a36Sopenharmony_ci	.notifier_call = keystone_platform_notifier,
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci#endif /* CONFIG_ARM_LPAE */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void __init keystone_init(void)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci#ifdef CONFIG_ARM_LPAE
9862306a36Sopenharmony_ci	if (PHYS_OFFSET >= KEYSTONE_HIGH_PHYS_START)
9962306a36Sopenharmony_ci		bus_register_notifier(&platform_bus_type, &platform_nb);
10062306a36Sopenharmony_ci#endif
10162306a36Sopenharmony_ci	keystone_pm_runtime_init();
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic long long __init keystone_pv_fixup(void)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	long long offset;
10762306a36Sopenharmony_ci	u64 mem_start, mem_end;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	mem_start = memblock_start_of_DRAM();
11062306a36Sopenharmony_ci	mem_end = memblock_end_of_DRAM();
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	/* nothing to do if we are running out of the <32-bit space */
11362306a36Sopenharmony_ci	if (mem_start >= KEYSTONE_LOW_PHYS_START &&
11462306a36Sopenharmony_ci	    mem_end   <= KEYSTONE_LOW_PHYS_END)
11562306a36Sopenharmony_ci		return 0;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (mem_start < KEYSTONE_HIGH_PHYS_START ||
11862306a36Sopenharmony_ci	    mem_end   > KEYSTONE_HIGH_PHYS_END) {
11962306a36Sopenharmony_ci		pr_crit("Invalid address space for memory (%08llx-%08llx)\n",
12062306a36Sopenharmony_ci		        mem_start, mem_end);
12162306a36Sopenharmony_ci		return 0;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	offset = KEYSTONE_HIGH_PHYS_START - KEYSTONE_LOW_PHYS_START;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Populate the arch idmap hook */
12762306a36Sopenharmony_ci	arch_phys_to_idmap_offset = -offset;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	return offset;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic const char *const keystone_match[] __initconst = {
13362306a36Sopenharmony_ci	"ti,k2hk",
13462306a36Sopenharmony_ci	"ti,k2e",
13562306a36Sopenharmony_ci	"ti,k2l",
13662306a36Sopenharmony_ci	"ti,k2g",
13762306a36Sopenharmony_ci	"ti,keystone",
13862306a36Sopenharmony_ci	NULL,
13962306a36Sopenharmony_ci};
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciDT_MACHINE_START(KEYSTONE, "Keystone")
14262306a36Sopenharmony_ci#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
14362306a36Sopenharmony_ci	.dma_zone_size	= SZ_2G,
14462306a36Sopenharmony_ci#endif
14562306a36Sopenharmony_ci	.init_machine	= keystone_init,
14662306a36Sopenharmony_ci	.dt_compat	= keystone_match,
14762306a36Sopenharmony_ci	.pv_fixup	= keystone_pv_fixup,
14862306a36Sopenharmony_ciMACHINE_END
149