18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * arch/powerpc/platforms/83xx/mpc832x_rdb.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Description:
88c2ecf20Sopenharmony_ci * MPC832x RDB board specific routines.
98c2ecf20Sopenharmony_ci * This file is based on mpc832x_mds.c and mpc8313_rdb.c
108c2ecf20Sopenharmony_ci * Author: Michael Barkowski <michael.barkowski@freescale.com>
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/pci.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
168c2ecf20Sopenharmony_ci#include <linux/spi/mmc_spi.h>
178c2ecf20Sopenharmony_ci#include <linux/mmc/host.h>
188c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
198c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/time.h>
228c2ecf20Sopenharmony_ci#include <asm/ipic.h>
238c2ecf20Sopenharmony_ci#include <asm/udbg.h>
248c2ecf20Sopenharmony_ci#include <soc/fsl/qe/qe.h>
258c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h>
268c2ecf20Sopenharmony_ci#include <sysdev/fsl_pci.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "mpc83xx.h"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#undef DEBUG
318c2ecf20Sopenharmony_ci#ifdef DEBUG
328c2ecf20Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt)
338c2ecf20Sopenharmony_ci#else
348c2ecf20Sopenharmony_ci#define DBG(fmt...)
358c2ecf20Sopenharmony_ci#endif
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE
388c2ecf20Sopenharmony_cistatic int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
398c2ecf20Sopenharmony_ci				   struct spi_board_info *board_infos,
408c2ecf20Sopenharmony_ci				   unsigned int num_board_infos,
418c2ecf20Sopenharmony_ci				   void (*cs_control)(struct spi_device *dev,
428c2ecf20Sopenharmony_ci						      bool on))
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct device_node *np;
458c2ecf20Sopenharmony_ci	unsigned int i = 0;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	for_each_compatible_node(np, type, compatible) {
488c2ecf20Sopenharmony_ci		int ret;
498c2ecf20Sopenharmony_ci		unsigned int j;
508c2ecf20Sopenharmony_ci		const void *prop;
518c2ecf20Sopenharmony_ci		struct resource res[2];
528c2ecf20Sopenharmony_ci		struct platform_device *pdev;
538c2ecf20Sopenharmony_ci		struct fsl_spi_platform_data pdata = {
548c2ecf20Sopenharmony_ci			.cs_control = cs_control,
558c2ecf20Sopenharmony_ci		};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		memset(res, 0, sizeof(res));
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		pdata.sysclk = sysclk;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci		prop = of_get_property(np, "reg", NULL);
628c2ecf20Sopenharmony_ci		if (!prop)
638c2ecf20Sopenharmony_ci			goto err;
648c2ecf20Sopenharmony_ci		pdata.bus_num = *(u32 *)prop;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		prop = of_get_property(np, "cell-index", NULL);
678c2ecf20Sopenharmony_ci		if (prop)
688c2ecf20Sopenharmony_ci			i = *(u32 *)prop;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		prop = of_get_property(np, "mode", NULL);
718c2ecf20Sopenharmony_ci		if (prop && !strcmp(prop, "cpu-qe"))
728c2ecf20Sopenharmony_ci			pdata.flags = SPI_QE_CPU_MODE;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		for (j = 0; j < num_board_infos; j++) {
758c2ecf20Sopenharmony_ci			if (board_infos[j].bus_num == pdata.bus_num)
768c2ecf20Sopenharmony_ci				pdata.max_chipselect++;
778c2ecf20Sopenharmony_ci		}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		if (!pdata.max_chipselect)
808c2ecf20Sopenharmony_ci			continue;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci		ret = of_address_to_resource(np, 0, &res[0]);
838c2ecf20Sopenharmony_ci		if (ret)
848c2ecf20Sopenharmony_ci			goto err;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		ret = of_irq_to_resource(np, 0, &res[1]);
878c2ecf20Sopenharmony_ci		if (ret <= 0)
888c2ecf20Sopenharmony_ci			goto err;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		pdev = platform_device_alloc("mpc83xx_spi", i);
918c2ecf20Sopenharmony_ci		if (!pdev)
928c2ecf20Sopenharmony_ci			goto err;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		ret = platform_device_add_data(pdev, &pdata, sizeof(pdata));
958c2ecf20Sopenharmony_ci		if (ret)
968c2ecf20Sopenharmony_ci			goto unreg;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		ret = platform_device_add_resources(pdev, res,
998c2ecf20Sopenharmony_ci						    ARRAY_SIZE(res));
1008c2ecf20Sopenharmony_ci		if (ret)
1018c2ecf20Sopenharmony_ci			goto unreg;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci		ret = platform_device_add(pdev);
1048c2ecf20Sopenharmony_ci		if (ret)
1058c2ecf20Sopenharmony_ci			goto unreg;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci		goto next;
1088c2ecf20Sopenharmony_ciunreg:
1098c2ecf20Sopenharmony_ci		platform_device_put(pdev);
1108c2ecf20Sopenharmony_cierr:
1118c2ecf20Sopenharmony_ci		pr_err("%pOF: registration failed\n", np);
1128c2ecf20Sopenharmony_cinext:
1138c2ecf20Sopenharmony_ci		i++;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return i;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int __init fsl_spi_init(struct spi_board_info *board_infos,
1208c2ecf20Sopenharmony_ci			       unsigned int num_board_infos,
1218c2ecf20Sopenharmony_ci			       void (*cs_control)(struct spi_device *spi,
1228c2ecf20Sopenharmony_ci						  bool on))
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	u32 sysclk = -1;
1258c2ecf20Sopenharmony_ci	int ret;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* SPI controller is either clocked from QE or SoC clock */
1288c2ecf20Sopenharmony_ci	sysclk = get_brgfreq();
1298c2ecf20Sopenharmony_ci	if (sysclk == -1) {
1308c2ecf20Sopenharmony_ci		sysclk = fsl_get_sys_freq();
1318c2ecf20Sopenharmony_ci		if (sysclk == -1)
1328c2ecf20Sopenharmony_ci			return -ENODEV;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
1368c2ecf20Sopenharmony_ci			       num_board_infos, cs_control);
1378c2ecf20Sopenharmony_ci	if (!ret)
1388c2ecf20Sopenharmony_ci		of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
1398c2ecf20Sopenharmony_ci				 num_board_infos, cs_control);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return spi_register_board_info(board_infos, num_board_infos);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic void mpc83xx_spi_cs_control(struct spi_device *spi, bool on)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	pr_debug("%s %d %d\n", __func__, spi->chip_select, on);
1478c2ecf20Sopenharmony_ci	par_io_data_set(3, 13, on);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic struct mmc_spi_platform_data mpc832x_mmc_pdata = {
1518c2ecf20Sopenharmony_ci	.ocr_mask = MMC_VDD_33_34,
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic struct spi_board_info mpc832x_spi_boardinfo = {
1558c2ecf20Sopenharmony_ci	.bus_num = 0x4c0,
1568c2ecf20Sopenharmony_ci	.chip_select = 0,
1578c2ecf20Sopenharmony_ci	.max_speed_hz = 50000000,
1588c2ecf20Sopenharmony_ci	.modalias = "mmc_spi",
1598c2ecf20Sopenharmony_ci	.platform_data = &mpc832x_mmc_pdata,
1608c2ecf20Sopenharmony_ci};
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic int __init mpc832x_spi_init(void)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	par_io_config_pin(3,  0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */
1658c2ecf20Sopenharmony_ci	par_io_config_pin(3,  1, 3, 0, 1, 0); /* SPI1 MISO, I/O */
1668c2ecf20Sopenharmony_ci	par_io_config_pin(3,  2, 3, 0, 1, 0); /* SPI1 CLK,  I/O */
1678c2ecf20Sopenharmony_ci	par_io_config_pin(3,  3, 2, 0, 1, 0); /* SPI1 SEL,  I   */
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	par_io_config_pin(3, 13, 1, 0, 0, 0); /* !SD_CS,    O */
1708c2ecf20Sopenharmony_ci	par_io_config_pin(3, 14, 2, 0, 0, 0); /* SD_INSERT, I */
1718c2ecf20Sopenharmony_ci	par_io_config_pin(3, 15, 2, 0, 0, 0); /* SD_PROTECT,I */
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/*
1748c2ecf20Sopenharmony_ci	 * Don't bother with legacy stuff when device tree contains
1758c2ecf20Sopenharmony_ci	 * mmc-spi-slot node.
1768c2ecf20Sopenharmony_ci	 */
1778c2ecf20Sopenharmony_ci	if (of_find_compatible_node(NULL, NULL, "mmc-spi-slot"))
1788c2ecf20Sopenharmony_ci		return 0;
1798c2ecf20Sopenharmony_ci	return fsl_spi_init(&mpc832x_spi_boardinfo, 1, mpc83xx_spi_cs_control);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_cimachine_device_initcall(mpc832x_rdb, mpc832x_spi_init);
1828c2ecf20Sopenharmony_ci#endif /* CONFIG_QUICC_ENGINE */
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci/* ************************************************************************
1858c2ecf20Sopenharmony_ci *
1868c2ecf20Sopenharmony_ci * Setup the architecture
1878c2ecf20Sopenharmony_ci *
1888c2ecf20Sopenharmony_ci */
1898c2ecf20Sopenharmony_cistatic void __init mpc832x_rdb_setup_arch(void)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci#if defined(CONFIG_QUICC_ENGINE)
1928c2ecf20Sopenharmony_ci	struct device_node *np;
1938c2ecf20Sopenharmony_ci#endif
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	mpc83xx_setup_arch();
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci#ifdef CONFIG_QUICC_ENGINE
1988c2ecf20Sopenharmony_ci	if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
1998c2ecf20Sopenharmony_ci		par_io_init(np);
2008c2ecf20Sopenharmony_ci		of_node_put(np);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		for_each_node_by_name(np, "ucc")
2038c2ecf20Sopenharmony_ci			par_io_of_config(np);
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci#endif				/* CONFIG_QUICC_ENGINE */
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cimachine_device_initcall(mpc832x_rdb, mpc83xx_declare_of_platform_devices);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * Called very early, MMU is off, device-tree isn't unflattened
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic int __init mpc832x_rdb_probe(void)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	return of_machine_is_compatible("MPC832xRDB");
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cidefine_machine(mpc832x_rdb) {
2198c2ecf20Sopenharmony_ci	.name		= "MPC832x RDB",
2208c2ecf20Sopenharmony_ci	.probe		= mpc832x_rdb_probe,
2218c2ecf20Sopenharmony_ci	.setup_arch	= mpc832x_rdb_setup_arch,
2228c2ecf20Sopenharmony_ci	.init_IRQ	= mpc83xx_ipic_init_IRQ,
2238c2ecf20Sopenharmony_ci	.get_irq	= ipic_get_irq,
2248c2ecf20Sopenharmony_ci	.restart	= mpc83xx_restart,
2258c2ecf20Sopenharmony_ci	.time_init	= mpc83xx_time_init,
2268c2ecf20Sopenharmony_ci	.calibrate_decr	= generic_calibrate_decr,
2278c2ecf20Sopenharmony_ci	.progress	= udbg_progress,
2288c2ecf20Sopenharmony_ci};
229