162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/sh/drivers/superhyway/ops-sh4-202.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * SuperHyway bus support for SH4-202
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2005  Paul Mundt
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/superhyway.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <asm/addrspace.h>
1462306a36Sopenharmony_ci#include <asm/io.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define PHYS_EMI_CBLOCK		P4SEGADDR(0x1ec00000)
1762306a36Sopenharmony_ci#define PHYS_EMI_DBLOCK		P4SEGADDR(0x08000000)
1862306a36Sopenharmony_ci#define PHYS_FEMI_CBLOCK	P4SEGADDR(0x1f800000)
1962306a36Sopenharmony_ci#define PHYS_FEMI_DBLOCK	P4SEGADDR(0x00000000)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define PHYS_EPBR_BLOCK		P4SEGADDR(0x1de00000)
2262306a36Sopenharmony_ci#define PHYS_DMAC_BLOCK		P4SEGADDR(0x1fa00000)
2362306a36Sopenharmony_ci#define PHYS_PBR_BLOCK		P4SEGADDR(0x1fc00000)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct resource emi_resources[] = {
2662306a36Sopenharmony_ci	[0] = {
2762306a36Sopenharmony_ci		.start	= PHYS_EMI_CBLOCK,
2862306a36Sopenharmony_ci		.end	= PHYS_EMI_CBLOCK + 0x00300000 - 1,
2962306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
3062306a36Sopenharmony_ci	},
3162306a36Sopenharmony_ci	[1] = {
3262306a36Sopenharmony_ci		.start	= PHYS_EMI_DBLOCK,
3362306a36Sopenharmony_ci		.end	= PHYS_EMI_DBLOCK + 0x08000000 - 1,
3462306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
3562306a36Sopenharmony_ci	},
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic struct superhyway_device emi_device = {
3962306a36Sopenharmony_ci	.name		= "emi",
4062306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(emi_resources),
4162306a36Sopenharmony_ci	.resource	= emi_resources,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct resource femi_resources[] = {
4562306a36Sopenharmony_ci	[0] = {
4662306a36Sopenharmony_ci		.start	= PHYS_FEMI_CBLOCK,
4762306a36Sopenharmony_ci		.end	= PHYS_FEMI_CBLOCK + 0x00100000 - 1,
4862306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
4962306a36Sopenharmony_ci	},
5062306a36Sopenharmony_ci	[1] = {
5162306a36Sopenharmony_ci		.start	= PHYS_FEMI_DBLOCK,
5262306a36Sopenharmony_ci		.end	= PHYS_FEMI_DBLOCK + 0x08000000 - 1,
5362306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
5462306a36Sopenharmony_ci	},
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic struct superhyway_device femi_device = {
5862306a36Sopenharmony_ci	.name		= "femi",
5962306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(femi_resources),
6062306a36Sopenharmony_ci	.resource	= femi_resources,
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic struct resource epbr_resources[] = {
6462306a36Sopenharmony_ci	[0] = {
6562306a36Sopenharmony_ci		.start	= P4SEGADDR(0x1e7ffff8),
6662306a36Sopenharmony_ci		.end	= P4SEGADDR(0x1e7ffff8 + (sizeof(u32) * 2) - 1),
6762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
6862306a36Sopenharmony_ci	},
6962306a36Sopenharmony_ci	[1] = {
7062306a36Sopenharmony_ci		.start	= PHYS_EPBR_BLOCK,
7162306a36Sopenharmony_ci		.end	= PHYS_EPBR_BLOCK + 0x00a00000 - 1,
7262306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
7362306a36Sopenharmony_ci	},
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic struct superhyway_device epbr_device = {
7762306a36Sopenharmony_ci	.name		= "epbr",
7862306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(epbr_resources),
7962306a36Sopenharmony_ci	.resource	= epbr_resources,
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic struct resource dmac_resource = {
8362306a36Sopenharmony_ci	.start	= PHYS_DMAC_BLOCK,
8462306a36Sopenharmony_ci	.end	= PHYS_DMAC_BLOCK + 0x00100000 - 1,
8562306a36Sopenharmony_ci	.flags	= IORESOURCE_MEM,
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic struct superhyway_device dmac_device = {
8962306a36Sopenharmony_ci	.name		= "dmac",
9062306a36Sopenharmony_ci	.num_resources	= 1,
9162306a36Sopenharmony_ci	.resource	= &dmac_resource,
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic struct resource pbr_resources[] = {
9562306a36Sopenharmony_ci	[0] = {
9662306a36Sopenharmony_ci		.start	= P4SEGADDR(0x1ffffff8),
9762306a36Sopenharmony_ci		.end	= P4SEGADDR(0x1ffffff8 + (sizeof(u32) * 2) - 1),
9862306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
9962306a36Sopenharmony_ci	},
10062306a36Sopenharmony_ci	[1] = {
10162306a36Sopenharmony_ci		.start	= PHYS_PBR_BLOCK,
10262306a36Sopenharmony_ci		.end	= PHYS_PBR_BLOCK + 0x00400000 - (sizeof(u32) * 2) - 1,
10362306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,
10462306a36Sopenharmony_ci	},
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic struct superhyway_device pbr_device = {
10862306a36Sopenharmony_ci	.name		= "pbr",
10962306a36Sopenharmony_ci	.num_resources	= ARRAY_SIZE(pbr_resources),
11062306a36Sopenharmony_ci	.resource	= pbr_resources,
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic struct superhyway_device *sh4202_devices[] __initdata = {
11462306a36Sopenharmony_ci	&emi_device, &femi_device, &epbr_device, &dmac_device, &pbr_device,
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic int sh4202_read_vcr(unsigned long base, struct superhyway_vcr_info *vcr)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 vcrh, vcrl;
12062306a36Sopenharmony_ci	u64 tmp;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * XXX: Even though the SH4-202 Evaluation Device documentation
12462306a36Sopenharmony_ci	 * indicates that VCRL is mapped first with VCRH at a + 0x04
12562306a36Sopenharmony_ci	 * offset, the opposite seems to be true.
12662306a36Sopenharmony_ci	 *
12762306a36Sopenharmony_ci	 * Some modules (PBR and ePBR for instance) also appear to have
12862306a36Sopenharmony_ci	 * VCRL/VCRH flipped in the documentation, but on the SH4-202
12962306a36Sopenharmony_ci	 * itself it appears that these are all consistently mapped with
13062306a36Sopenharmony_ci	 * VCRH preceding VCRL.
13162306a36Sopenharmony_ci	 *
13262306a36Sopenharmony_ci	 * Do not trust the documentation, for it is evil.
13362306a36Sopenharmony_ci	 */
13462306a36Sopenharmony_ci	vcrh = __raw_readl(base);
13562306a36Sopenharmony_ci	vcrl = __raw_readl(base + sizeof(u32));
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	tmp = ((u64)vcrh << 32) | vcrl;
13862306a36Sopenharmony_ci	memcpy(vcr, &tmp, sizeof(u64));
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int sh4202_write_vcr(unsigned long base, struct superhyway_vcr_info vcr)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	u64 tmp = *(u64 *)&vcr;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	__raw_writel((tmp >> 32) & 0xffffffff, base);
14862306a36Sopenharmony_ci	__raw_writel(tmp & 0xffffffff, base + sizeof(u32));
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return 0;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic struct superhyway_ops sh4202_superhyway_ops = {
15462306a36Sopenharmony_ci	.read_vcr	= sh4202_read_vcr,
15562306a36Sopenharmony_ci	.write_vcr	= sh4202_write_vcr,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistruct superhyway_bus superhyway_channels[] = {
15962306a36Sopenharmony_ci	{ &sh4202_superhyway_ops, },
16062306a36Sopenharmony_ci	{ 0, },
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciint __init superhyway_scan_bus(struct superhyway_bus *bus)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	return superhyway_add_devices(bus, sh4202_devices,
16662306a36Sopenharmony_ci				      ARRAY_SIZE(sh4202_devices));
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
169