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