cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

oxnas_nand.c (4932B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Oxford Semiconductor OXNAS NAND driver
      4
      5 * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
      6 * Heavily based on plat_nand.c :
      7 * Author: Vitaly Wool <vitalywool@gmail.com>
      8 * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
      9 * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
     10 */
     11
     12#include <linux/err.h>
     13#include <linux/io.h>
     14#include <linux/module.h>
     15#include <linux/platform_device.h>
     16#include <linux/slab.h>
     17#include <linux/clk.h>
     18#include <linux/reset.h>
     19#include <linux/mtd/mtd.h>
     20#include <linux/mtd/rawnand.h>
     21#include <linux/mtd/partitions.h>
     22#include <linux/of.h>
     23
     24/* Nand commands */
     25#define OXNAS_NAND_CMD_ALE		BIT(18)
     26#define OXNAS_NAND_CMD_CLE		BIT(19)
     27
     28#define OXNAS_NAND_MAX_CHIPS	1
     29
     30struct oxnas_nand_ctrl {
     31	struct nand_controller base;
     32	void __iomem *io_base;
     33	struct clk *clk;
     34	struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
     35	unsigned int nchips;
     36};
     37
     38static uint8_t oxnas_nand_read_byte(struct nand_chip *chip)
     39{
     40	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
     41
     42	return readb(oxnas->io_base);
     43}
     44
     45static void oxnas_nand_read_buf(struct nand_chip *chip, u8 *buf, int len)
     46{
     47	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
     48
     49	ioread8_rep(oxnas->io_base, buf, len);
     50}
     51
     52static void oxnas_nand_write_buf(struct nand_chip *chip, const u8 *buf,
     53				 int len)
     54{
     55	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
     56
     57	iowrite8_rep(oxnas->io_base, buf, len);
     58}
     59
     60/* Single CS command control */
     61static void oxnas_nand_cmd_ctrl(struct nand_chip *chip, int cmd,
     62				unsigned int ctrl)
     63{
     64	struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip);
     65
     66	if (ctrl & NAND_CLE)
     67		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE);
     68	else if (ctrl & NAND_ALE)
     69		writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE);
     70}
     71
     72/*
     73 * Probe for the NAND device.
     74 */
     75static int oxnas_nand_probe(struct platform_device *pdev)
     76{
     77	struct device_node *np = pdev->dev.of_node;
     78	struct device_node *nand_np;
     79	struct oxnas_nand_ctrl *oxnas;
     80	struct nand_chip *chip;
     81	struct mtd_info *mtd;
     82	int count = 0;
     83	int err = 0;
     84	int i;
     85
     86	/* Allocate memory for the device structure (and zero it) */
     87	oxnas = devm_kzalloc(&pdev->dev, sizeof(*oxnas),
     88			     GFP_KERNEL);
     89	if (!oxnas)
     90		return -ENOMEM;
     91
     92	nand_controller_init(&oxnas->base);
     93
     94	oxnas->io_base = devm_platform_ioremap_resource(pdev, 0);
     95	if (IS_ERR(oxnas->io_base))
     96		return PTR_ERR(oxnas->io_base);
     97
     98	oxnas->clk = devm_clk_get(&pdev->dev, NULL);
     99	if (IS_ERR(oxnas->clk))
    100		oxnas->clk = NULL;
    101
    102	/* Only a single chip node is supported */
    103	count = of_get_child_count(np);
    104	if (count > 1)
    105		return -EINVAL;
    106
    107	err = clk_prepare_enable(oxnas->clk);
    108	if (err)
    109		return err;
    110
    111	device_reset_optional(&pdev->dev);
    112
    113	for_each_child_of_node(np, nand_np) {
    114		chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
    115				    GFP_KERNEL);
    116		if (!chip) {
    117			err = -ENOMEM;
    118			goto err_release_child;
    119		}
    120
    121		chip->controller = &oxnas->base;
    122
    123		nand_set_flash_node(chip, nand_np);
    124		nand_set_controller_data(chip, oxnas);
    125
    126		mtd = nand_to_mtd(chip);
    127		mtd->dev.parent = &pdev->dev;
    128		mtd->priv = chip;
    129
    130		chip->legacy.cmd_ctrl = oxnas_nand_cmd_ctrl;
    131		chip->legacy.read_buf = oxnas_nand_read_buf;
    132		chip->legacy.read_byte = oxnas_nand_read_byte;
    133		chip->legacy.write_buf = oxnas_nand_write_buf;
    134		chip->legacy.chip_delay = 30;
    135
    136		/* Scan to find existence of the device */
    137		err = nand_scan(chip, 1);
    138		if (err)
    139			goto err_release_child;
    140
    141		err = mtd_device_register(mtd, NULL, 0);
    142		if (err)
    143			goto err_cleanup_nand;
    144
    145		oxnas->chips[oxnas->nchips++] = chip;
    146	}
    147
    148	/* Exit if no chips found */
    149	if (!oxnas->nchips) {
    150		err = -ENODEV;
    151		goto err_clk_unprepare;
    152	}
    153
    154	platform_set_drvdata(pdev, oxnas);
    155
    156	return 0;
    157
    158err_cleanup_nand:
    159	nand_cleanup(chip);
    160err_release_child:
    161	of_node_put(nand_np);
    162
    163	for (i = 0; i < oxnas->nchips; i++) {
    164		chip = oxnas->chips[i];
    165		WARN_ON(mtd_device_unregister(nand_to_mtd(chip)));
    166		nand_cleanup(chip);
    167	}
    168
    169err_clk_unprepare:
    170	clk_disable_unprepare(oxnas->clk);
    171	return err;
    172}
    173
    174static int oxnas_nand_remove(struct platform_device *pdev)
    175{
    176	struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev);
    177	struct nand_chip *chip;
    178	int i;
    179
    180	for (i = 0; i < oxnas->nchips; i++) {
    181		chip = oxnas->chips[i];
    182		WARN_ON(mtd_device_unregister(nand_to_mtd(chip)));
    183		nand_cleanup(chip);
    184	}
    185
    186	clk_disable_unprepare(oxnas->clk);
    187
    188	return 0;
    189}
    190
    191static const struct of_device_id oxnas_nand_match[] = {
    192	{ .compatible = "oxsemi,ox820-nand" },
    193	{},
    194};
    195MODULE_DEVICE_TABLE(of, oxnas_nand_match);
    196
    197static struct platform_driver oxnas_nand_driver = {
    198	.probe	= oxnas_nand_probe,
    199	.remove	= oxnas_nand_remove,
    200	.driver	= {
    201		.name		= "oxnas_nand",
    202		.of_match_table = oxnas_nand_match,
    203	},
    204};
    205
    206module_platform_driver(oxnas_nand_driver);
    207
    208MODULE_LICENSE("GPL");
    209MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
    210MODULE_DESCRIPTION("Oxnas NAND driver");
    211MODULE_ALIAS("platform:oxnas_nand");