162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * arch/powerpc/platforms/83xx/mpc832x_rdb.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Description:
862306a36Sopenharmony_ci * MPC832x RDB board specific routines.
962306a36Sopenharmony_ci * This file is based on mpc832x_mds.c and mpc8313_rdb.c
1062306a36Sopenharmony_ci * Author: Michael Barkowski <michael.barkowski@freescale.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/pci.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/spi/spi.h>
1662306a36Sopenharmony_ci#include <linux/spi/mmc_spi.h>
1762306a36Sopenharmony_ci#include <linux/mmc/host.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/of_address.h>
2062306a36Sopenharmony_ci#include <linux/of_irq.h>
2162306a36Sopenharmony_ci#include <linux/platform_device.h>
2262306a36Sopenharmony_ci#include <linux/fsl_devices.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/time.h>
2562306a36Sopenharmony_ci#include <asm/ipic.h>
2662306a36Sopenharmony_ci#include <asm/udbg.h>
2762306a36Sopenharmony_ci#include <soc/fsl/qe/qe.h>
2862306a36Sopenharmony_ci#include <sysdev/fsl_soc.h>
2962306a36Sopenharmony_ci#include <sysdev/fsl_pci.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "mpc83xx.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#undef DEBUG
3462306a36Sopenharmony_ci#ifdef DEBUG
3562306a36Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt)
3662306a36Sopenharmony_ci#else
3762306a36Sopenharmony_ci#define DBG(fmt...)
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE
4162306a36Sopenharmony_cistatic int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
4262306a36Sopenharmony_ci				   struct spi_board_info *board_infos,
4362306a36Sopenharmony_ci				   unsigned int num_board_infos,
4462306a36Sopenharmony_ci				   void (*cs_control)(struct spi_device *dev,
4562306a36Sopenharmony_ci						      bool on))
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct device_node *np;
4862306a36Sopenharmony_ci	unsigned int i = 0;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	for_each_compatible_node(np, type, compatible) {
5162306a36Sopenharmony_ci		int ret;
5262306a36Sopenharmony_ci		unsigned int j;
5362306a36Sopenharmony_ci		const void *prop;
5462306a36Sopenharmony_ci		struct resource res[2];
5562306a36Sopenharmony_ci		struct platform_device *pdev;
5662306a36Sopenharmony_ci		struct fsl_spi_platform_data pdata = {
5762306a36Sopenharmony_ci			.cs_control = cs_control,
5862306a36Sopenharmony_ci		};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		memset(res, 0, sizeof(res));
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		pdata.sysclk = sysclk;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		prop = of_get_property(np, "reg", NULL);
6562306a36Sopenharmony_ci		if (!prop)
6662306a36Sopenharmony_ci			goto err;
6762306a36Sopenharmony_ci		pdata.bus_num = *(u32 *)prop;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		prop = of_get_property(np, "cell-index", NULL);
7062306a36Sopenharmony_ci		if (prop)
7162306a36Sopenharmony_ci			i = *(u32 *)prop;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		prop = of_get_property(np, "mode", NULL);
7462306a36Sopenharmony_ci		if (prop && !strcmp(prop, "cpu-qe"))
7562306a36Sopenharmony_ci			pdata.flags = SPI_QE_CPU_MODE;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci		for (j = 0; j < num_board_infos; j++) {
7862306a36Sopenharmony_ci			if (board_infos[j].bus_num == pdata.bus_num)
7962306a36Sopenharmony_ci				pdata.max_chipselect++;
8062306a36Sopenharmony_ci		}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci		if (!pdata.max_chipselect)
8362306a36Sopenharmony_ci			continue;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci		ret = of_address_to_resource(np, 0, &res[0]);
8662306a36Sopenharmony_ci		if (ret)
8762306a36Sopenharmony_ci			goto err;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		ret = of_irq_to_resource(np, 0, &res[1]);
9062306a36Sopenharmony_ci		if (ret <= 0)
9162306a36Sopenharmony_ci			goto err;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		pdev = platform_device_alloc("mpc83xx_spi", i);
9462306a36Sopenharmony_ci		if (!pdev)
9562306a36Sopenharmony_ci			goto err;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
9862306a36Sopenharmony_ci		if (ret)
9962306a36Sopenharmony_ci			goto unreg;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		ret = platform_device_add_resources(pdev, res,
10262306a36Sopenharmony_ci						    ARRAY_SIZE(res));
10362306a36Sopenharmony_ci		if (ret)
10462306a36Sopenharmony_ci			goto unreg;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		ret = platform_device_add(pdev);
10762306a36Sopenharmony_ci		if (ret)
10862306a36Sopenharmony_ci			goto unreg;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		goto next;
11162306a36Sopenharmony_ciunreg:
11262306a36Sopenharmony_ci		platform_device_put(pdev);
11362306a36Sopenharmony_cierr:
11462306a36Sopenharmony_ci		pr_err("%pOF: registration failed\n", np);
11562306a36Sopenharmony_cinext:
11662306a36Sopenharmony_ci		i++;
11762306a36Sopenharmony_ci	}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return i;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int __init fsl_spi_init(struct spi_board_info *board_infos,
12362306a36Sopenharmony_ci			       unsigned int num_board_infos,
12462306a36Sopenharmony_ci			       void (*cs_control)(struct spi_device *spi,
12562306a36Sopenharmony_ci						  bool on))
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	u32 sysclk = -1;
12862306a36Sopenharmony_ci	int ret;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* SPI controller is either clocked from QE or SoC clock */
13162306a36Sopenharmony_ci	sysclk = get_brgfreq();
13262306a36Sopenharmony_ci	if (sysclk == -1) {
13362306a36Sopenharmony_ci		sysclk = fsl_get_sys_freq();
13462306a36Sopenharmony_ci		if (sysclk == -1)
13562306a36Sopenharmony_ci			return -ENODEV;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
13962306a36Sopenharmony_ci			       num_board_infos, cs_control);
14062306a36Sopenharmony_ci	if (!ret)
14162306a36Sopenharmony_ci		of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
14262306a36Sopenharmony_ci				 num_board_infos, cs_control);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return spi_register_board_info(board_infos, num_board_infos);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	pr_debug("%s %d %d\n", __func__, spi_get_chipselect(spi, 0), on);
15062306a36Sopenharmony_ci	par_io_data_set(3, 13, on);
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic struct mmc_spi_platform_data mpc832x_mmc_pdata = {
15462306a36Sopenharmony_ci	.ocr_mask = MMC_VDD_33_34,
15562306a36Sopenharmony_ci};
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic struct spi_board_info mpc832x_spi_boardinfo = {
15862306a36Sopenharmony_ci	.bus_num = 0x4c0,
15962306a36Sopenharmony_ci	.chip_select = 0,
16062306a36Sopenharmony_ci	.max_speed_hz = 50000000,
16162306a36Sopenharmony_ci	.modalias = "mmc_spi",
16262306a36Sopenharmony_ci	.platform_data = &mpc832x_mmc_pdata,
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int __init mpc832x_spi_init(void)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct device_node *np;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	par_io_config_pin(3,  0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */
17062306a36Sopenharmony_ci	par_io_config_pin(3,  1, 3, 0, 1, 0); /* SPI1 MISO, I/O */
17162306a36Sopenharmony_ci	par_io_config_pin(3,  2, 3, 0, 1, 0); /* SPI1 CLK,  I/O */
17262306a36Sopenharmony_ci	par_io_config_pin(3,  3, 2, 0, 1, 0); /* SPI1 SEL,  I   */
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	par_io_config_pin(3, 13, 1, 0, 0, 0); /* !SD_CS,    O */
17562306a36Sopenharmony_ci	par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */
17662306a36Sopenharmony_ci	par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/*
17962306a36Sopenharmony_ci	 * Don't bother with legacy stuff when device tree contains
18062306a36Sopenharmony_ci	 * mmc-spi-slot node.
18162306a36Sopenharmony_ci	 */
18262306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "mmc-spi-slot");
18362306a36Sopenharmony_ci	of_node_put(np);
18462306a36Sopenharmony_ci	if (np)
18562306a36Sopenharmony_ci		return 0;
18662306a36Sopenharmony_ci	return fsl_spi_init(&mpc832x_spi_boardinfo, 1, mpc83xx_spi_cs_control);
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_cimachine_device_initcall(mpc832x_rdb, mpc832x_spi_init);
18962306a36Sopenharmony_ci#endif /* CONFIG_QUICC_ENGINE */
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* ************************************************************************
19262306a36Sopenharmony_ci *
19362306a36Sopenharmony_ci * Setup the architecture
19462306a36Sopenharmony_ci *
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic void __init mpc832x_rdb_setup_arch(void)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci#if defined(CONFIG_QUICC_ENGINE)
19962306a36Sopenharmony_ci	struct device_node *np;
20062306a36Sopenharmony_ci#endif
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	mpc83xx_setup_arch();
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE
20562306a36Sopenharmony_ci	if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
20662306a36Sopenharmony_ci		par_io_init(np);
20762306a36Sopenharmony_ci		of_node_put(np);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		for_each_node_by_name(np, "ucc")
21062306a36Sopenharmony_ci			par_io_of_config(np);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci#endif				/* CONFIG_QUICC_ENGINE */
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cimachine_device_initcall(mpc832x_rdb, mpc83xx_declare_of_platform_devices);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cidefine_machine(mpc832x_rdb) {
21862306a36Sopenharmony_ci	.name		= "MPC832x RDB",
21962306a36Sopenharmony_ci	.compatible	= "MPC832xRDB",
22062306a36Sopenharmony_ci	.setup_arch	= mpc832x_rdb_setup_arch,
22162306a36Sopenharmony_ci	.discover_phbs  = mpc83xx_setup_pci,
22262306a36Sopenharmony_ci	.init_IRQ	= mpc83xx_ipic_init_IRQ,
22362306a36Sopenharmony_ci	.get_irq	= ipic_get_irq,
22462306a36Sopenharmony_ci	.restart	= mpc83xx_restart,
22562306a36Sopenharmony_ci	.time_init	= mpc83xx_time_init,
22662306a36Sopenharmony_ci	.progress	= udbg_progress,
22762306a36Sopenharmony_ci};
228