xref: /linux/drivers/mtd/nand/raw/brcmnand/bcma_nand.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1feca4cc4SFlorian Fainelli // SPDX-License-Identifier: GPL-2.0-only
2feca4cc4SFlorian Fainelli /*
3feca4cc4SFlorian Fainelli  * Copyright © 2021 Broadcom
4feca4cc4SFlorian Fainelli  */
5feca4cc4SFlorian Fainelli #include <linux/bcma/bcma.h>
6feca4cc4SFlorian Fainelli #include <linux/bcma/bcma_driver_chipcommon.h>
7feca4cc4SFlorian Fainelli #include <linux/device.h>
8feca4cc4SFlorian Fainelli #include <linux/module.h>
9feca4cc4SFlorian Fainelli #include <linux/platform_device.h>
10feca4cc4SFlorian Fainelli 
11feca4cc4SFlorian Fainelli #include "brcmnand.h"
12feca4cc4SFlorian Fainelli 
13feca4cc4SFlorian Fainelli struct brcmnand_bcma_soc {
14feca4cc4SFlorian Fainelli 	struct brcmnand_soc soc;
15feca4cc4SFlorian Fainelli 	struct bcma_drv_cc *cc;
16feca4cc4SFlorian Fainelli };
17feca4cc4SFlorian Fainelli 
brcmnand_bcma_needs_swapping(u32 offset)18feca4cc4SFlorian Fainelli static inline bool brcmnand_bcma_needs_swapping(u32 offset)
19feca4cc4SFlorian Fainelli {
20feca4cc4SFlorian Fainelli 	switch (offset) {
21feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD0:
22feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD4:
23feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD8:
24feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD12:
25feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_WR0:
26feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_WR4:
27feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_WR8:
28feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_WR12:
29feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_DEVID:
30feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_DEVID_X:
31feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD16:
32feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD20:
33feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD24:
34feca4cc4SFlorian Fainelli 	case BCMA_CC_NAND_SPARE_RD28:
35feca4cc4SFlorian Fainelli 		return true;
36feca4cc4SFlorian Fainelli 	}
37feca4cc4SFlorian Fainelli 
38feca4cc4SFlorian Fainelli 	return false;
39feca4cc4SFlorian Fainelli }
40feca4cc4SFlorian Fainelli 
to_bcma_soc(struct brcmnand_soc * soc)41feca4cc4SFlorian Fainelli static inline struct brcmnand_bcma_soc *to_bcma_soc(struct brcmnand_soc *soc)
42feca4cc4SFlorian Fainelli {
43feca4cc4SFlorian Fainelli 	return container_of(soc, struct brcmnand_bcma_soc, soc);
44feca4cc4SFlorian Fainelli }
45feca4cc4SFlorian Fainelli 
brcmnand_bcma_read_reg(struct brcmnand_soc * soc,u32 offset)46feca4cc4SFlorian Fainelli static u32 brcmnand_bcma_read_reg(struct brcmnand_soc *soc, u32 offset)
47feca4cc4SFlorian Fainelli {
48feca4cc4SFlorian Fainelli 	struct brcmnand_bcma_soc *sc = to_bcma_soc(soc);
49feca4cc4SFlorian Fainelli 	u32 val;
50feca4cc4SFlorian Fainelli 
51feca4cc4SFlorian Fainelli 	/* Offset into the NAND block and deal with the flash cache separately */
52feca4cc4SFlorian Fainelli 	if (offset == BRCMNAND_NON_MMIO_FC_ADDR)
53feca4cc4SFlorian Fainelli 		offset = BCMA_CC_NAND_CACHE_DATA;
54feca4cc4SFlorian Fainelli 	else
55feca4cc4SFlorian Fainelli 		offset += BCMA_CC_NAND_REVISION;
56feca4cc4SFlorian Fainelli 
57feca4cc4SFlorian Fainelli 	val = bcma_cc_read32(sc->cc, offset);
58feca4cc4SFlorian Fainelli 
59feca4cc4SFlorian Fainelli 	/* Swap if necessary */
60feca4cc4SFlorian Fainelli 	if (brcmnand_bcma_needs_swapping(offset))
61d430e4acSFlorian Fainelli 		val = be32_to_cpu((__force __be32)val);
62feca4cc4SFlorian Fainelli 	return val;
63feca4cc4SFlorian Fainelli }
64feca4cc4SFlorian Fainelli 
brcmnand_bcma_write_reg(struct brcmnand_soc * soc,u32 val,u32 offset)65feca4cc4SFlorian Fainelli static void brcmnand_bcma_write_reg(struct brcmnand_soc *soc, u32 val,
66feca4cc4SFlorian Fainelli 				    u32 offset)
67feca4cc4SFlorian Fainelli {
68feca4cc4SFlorian Fainelli 	struct brcmnand_bcma_soc *sc = to_bcma_soc(soc);
69feca4cc4SFlorian Fainelli 
70feca4cc4SFlorian Fainelli 	/* Offset into the NAND block */
71feca4cc4SFlorian Fainelli 	if (offset == BRCMNAND_NON_MMIO_FC_ADDR)
72feca4cc4SFlorian Fainelli 		offset = BCMA_CC_NAND_CACHE_DATA;
73feca4cc4SFlorian Fainelli 	else
74feca4cc4SFlorian Fainelli 		offset += BCMA_CC_NAND_REVISION;
75feca4cc4SFlorian Fainelli 
76feca4cc4SFlorian Fainelli 	/* Swap if necessary */
77feca4cc4SFlorian Fainelli 	if (brcmnand_bcma_needs_swapping(offset))
78d430e4acSFlorian Fainelli 		val = (__force u32)cpu_to_be32(val);
79feca4cc4SFlorian Fainelli 
80feca4cc4SFlorian Fainelli 	bcma_cc_write32(sc->cc, offset, val);
81feca4cc4SFlorian Fainelli }
82feca4cc4SFlorian Fainelli 
83feca4cc4SFlorian Fainelli static struct brcmnand_io_ops brcmnand_bcma_io_ops = {
84feca4cc4SFlorian Fainelli 	.read_reg	= brcmnand_bcma_read_reg,
85feca4cc4SFlorian Fainelli 	.write_reg	= brcmnand_bcma_write_reg,
86feca4cc4SFlorian Fainelli };
87feca4cc4SFlorian Fainelli 
brcmnand_bcma_prepare_data_bus(struct brcmnand_soc * soc,bool prepare,bool is_param)88feca4cc4SFlorian Fainelli static void brcmnand_bcma_prepare_data_bus(struct brcmnand_soc *soc, bool prepare,
89feca4cc4SFlorian Fainelli 					   bool is_param)
90feca4cc4SFlorian Fainelli {
91feca4cc4SFlorian Fainelli 	struct brcmnand_bcma_soc *sc = to_bcma_soc(soc);
92feca4cc4SFlorian Fainelli 
93feca4cc4SFlorian Fainelli 	/* Reset the cache address to ensure we are already accessing the
94feca4cc4SFlorian Fainelli 	 * beginning of a sub-page.
95feca4cc4SFlorian Fainelli 	 */
96feca4cc4SFlorian Fainelli 	bcma_cc_write32(sc->cc, BCMA_CC_NAND_CACHE_ADDR, 0);
97feca4cc4SFlorian Fainelli }
98feca4cc4SFlorian Fainelli 
brcmnand_bcma_nand_probe(struct platform_device * pdev)99feca4cc4SFlorian Fainelli static int brcmnand_bcma_nand_probe(struct platform_device *pdev)
100feca4cc4SFlorian Fainelli {
101feca4cc4SFlorian Fainelli 	struct bcma_nflash *nflash = dev_get_platdata(&pdev->dev);
102feca4cc4SFlorian Fainelli 	struct brcmnand_bcma_soc *soc;
103feca4cc4SFlorian Fainelli 
104feca4cc4SFlorian Fainelli 	soc = devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL);
105feca4cc4SFlorian Fainelli 	if (!soc)
106feca4cc4SFlorian Fainelli 		return -ENOMEM;
107feca4cc4SFlorian Fainelli 
108feca4cc4SFlorian Fainelli 	soc->cc = container_of(nflash, struct bcma_drv_cc, nflash);
109feca4cc4SFlorian Fainelli 	soc->soc.prepare_data_bus = brcmnand_bcma_prepare_data_bus;
110feca4cc4SFlorian Fainelli 	soc->soc.ops = &brcmnand_bcma_io_ops;
111feca4cc4SFlorian Fainelli 
112feca4cc4SFlorian Fainelli 	if (soc->cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
113feca4cc4SFlorian Fainelli 		dev_err(&pdev->dev, "Use bcm47xxnflash for 4706!\n");
114feca4cc4SFlorian Fainelli 		return -ENODEV;
115feca4cc4SFlorian Fainelli 	}
116feca4cc4SFlorian Fainelli 
117feca4cc4SFlorian Fainelli 	return brcmnand_probe(pdev, &soc->soc);
118feca4cc4SFlorian Fainelli }
119feca4cc4SFlorian Fainelli 
120feca4cc4SFlorian Fainelli static struct platform_driver brcmnand_bcma_nand_driver = {
121feca4cc4SFlorian Fainelli 	.probe			= brcmnand_bcma_nand_probe,
122*215283a1SUwe Kleine-König 	.remove_new		= brcmnand_remove,
123feca4cc4SFlorian Fainelli 	.driver = {
124feca4cc4SFlorian Fainelli 		.name		= "bcma_brcmnand",
125feca4cc4SFlorian Fainelli 		.pm		= &brcmnand_pm_ops,
126feca4cc4SFlorian Fainelli 	}
127feca4cc4SFlorian Fainelli };
128feca4cc4SFlorian Fainelli module_platform_driver(brcmnand_bcma_nand_driver);
129feca4cc4SFlorian Fainelli 
130feca4cc4SFlorian Fainelli MODULE_LICENSE("GPL v2");
131feca4cc4SFlorian Fainelli MODULE_AUTHOR("Broadcom");
132feca4cc4SFlorian Fainelli MODULE_DESCRIPTION("NAND controller driver glue for BCMA chips");
133