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