162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SDK7786 FPGA Support.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010  Paul Mundt
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/init.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/bcd.h>
1062306a36Sopenharmony_ci#include <mach/fpga.h>
1162306a36Sopenharmony_ci#include <linux/sizes.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define FPGA_REGS_OFFSET	0x03fff800
1462306a36Sopenharmony_ci#define FPGA_REGS_SIZE		0x490
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * The FPGA can be mapped in any of the generally available areas,
1862306a36Sopenharmony_ci * so we attempt to scan for it using the fixed SRSTR read magic.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Once the FPGA is located, the rest of the mapping data for the other
2162306a36Sopenharmony_ci * components can be determined dynamically from its section mapping
2262306a36Sopenharmony_ci * registers.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic void __iomem *sdk7786_fpga_probe(void)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	unsigned long area;
2762306a36Sopenharmony_ci	void __iomem *base;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	/*
3062306a36Sopenharmony_ci	 * Iterate over all of the areas where the FPGA could be mapped.
3162306a36Sopenharmony_ci	 * The possible range is anywhere from area 0 through 6, area 7
3262306a36Sopenharmony_ci	 * is reserved.
3362306a36Sopenharmony_ci	 */
3462306a36Sopenharmony_ci	for (area = PA_AREA0; area < PA_AREA7; area += SZ_64M) {
3562306a36Sopenharmony_ci		base = ioremap(area + FPGA_REGS_OFFSET, FPGA_REGS_SIZE);
3662306a36Sopenharmony_ci		if (!base) {
3762306a36Sopenharmony_ci			/* Failed to remap this area, move along. */
3862306a36Sopenharmony_ci			continue;
3962306a36Sopenharmony_ci		}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		if (ioread16(base + SRSTR) == SRSTR_MAGIC)
4262306a36Sopenharmony_ci			return base;	/* Found it! */
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci		iounmap(base);
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	return NULL;
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid __iomem *sdk7786_fpga_base;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_civoid __init sdk7786_fpga_init(void)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	u16 version, date;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	sdk7786_fpga_base = sdk7786_fpga_probe();
5762306a36Sopenharmony_ci	if (unlikely(!sdk7786_fpga_base)) {
5862306a36Sopenharmony_ci		panic("FPGA detection failed.\n");
5962306a36Sopenharmony_ci		return;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	version = fpga_read_reg(FPGAVR);
6362306a36Sopenharmony_ci	date = fpga_read_reg(FPGADR);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	pr_info("\tFPGA version:\t%d.%d (built on %d/%d/%d)\n",
6662306a36Sopenharmony_ci		bcd2bin(version >> 8) & 0xf, bcd2bin(version & 0xf),
6762306a36Sopenharmony_ci		((date >> 12) & 0xf) + 2000,
6862306a36Sopenharmony_ci		(date >> 8) & 0xf, bcd2bin(date & 0xff));
6962306a36Sopenharmony_ci}
70