mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 10:39:04 +00:00
050621aa01
This patch adds a new spi-nand driver which implements the SNFI of mt7622 and mt7629. Unlike the existing snfi driver which makes use of the spi-mem framework and the spi-nand framework with modified ecc support, this driver is implemented directly on the mtd framework with other components untouched, and provides better performance, and behaves exactly the same as the nand framework. Signed-off-by: Weijie Gao <hackpascal@gmail.com>
128 lines
2.9 KiB
C
128 lines
2.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
|
|
*
|
|
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
*/
|
|
|
|
#ifndef _MTK_SNAND_OS_H_
|
|
#define _MTK_SNAND_OS_H_
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/limits.h>
|
|
#include <linux/types.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/sizes.h>
|
|
#include <linux/iopoll.h>
|
|
#include <linux/hrtimer.h>
|
|
#include <linux/device.h>
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/io.h>
|
|
#include <asm/div64.h>
|
|
|
|
struct mtk_snand_plat_dev {
|
|
struct device *dev;
|
|
struct completion done;
|
|
};
|
|
|
|
/* Polling helpers */
|
|
#define read16_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
|
|
readw_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
|
|
|
|
#define read32_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
|
|
readl_poll_timeout((addr), (val), (cond), (sleep_us), (timeout_us))
|
|
|
|
/* Timer helpers */
|
|
#define mtk_snand_time_t ktime_t
|
|
|
|
static inline mtk_snand_time_t timer_get_ticks(void)
|
|
{
|
|
return ktime_get();
|
|
}
|
|
|
|
static inline mtk_snand_time_t timer_time_to_tick(uint32_t timeout_us)
|
|
{
|
|
return ktime_add_us(ktime_set(0, 0), timeout_us);
|
|
}
|
|
|
|
static inline bool timer_is_timeout(mtk_snand_time_t start_tick,
|
|
mtk_snand_time_t timeout_tick)
|
|
{
|
|
ktime_t tmo = ktime_add(start_tick, timeout_tick);
|
|
|
|
return ktime_compare(ktime_get(), tmo) > 0;
|
|
}
|
|
|
|
/* Memory helpers */
|
|
static inline void *generic_mem_alloc(struct mtk_snand_plat_dev *pdev,
|
|
size_t size)
|
|
{
|
|
return devm_kzalloc(pdev->dev, size, GFP_KERNEL);
|
|
}
|
|
static inline void generic_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
|
|
{
|
|
devm_kfree(pdev->dev, ptr);
|
|
}
|
|
|
|
static inline void *dma_mem_alloc(struct mtk_snand_plat_dev *pdev, size_t size)
|
|
{
|
|
return kzalloc(size, GFP_KERNEL);
|
|
}
|
|
static inline void dma_mem_free(struct mtk_snand_plat_dev *pdev, void *ptr)
|
|
{
|
|
kfree(ptr);
|
|
}
|
|
|
|
static inline int dma_mem_map(struct mtk_snand_plat_dev *pdev, void *vaddr,
|
|
uintptr_t *dma_addr, size_t size, bool to_device)
|
|
{
|
|
dma_addr_t addr;
|
|
int ret;
|
|
|
|
addr = dma_map_single(pdev->dev, vaddr, size,
|
|
to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
|
ret = dma_mapping_error(pdev->dev, addr);
|
|
if (ret)
|
|
return ret;
|
|
|
|
*dma_addr = (uintptr_t)addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void dma_mem_unmap(struct mtk_snand_plat_dev *pdev,
|
|
uintptr_t dma_addr, size_t size,
|
|
bool to_device)
|
|
{
|
|
dma_unmap_single(pdev->dev, dma_addr, size,
|
|
to_device ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
|
}
|
|
|
|
/* Interrupt helpers */
|
|
static inline void irq_completion_done(struct mtk_snand_plat_dev *pdev)
|
|
{
|
|
complete(&pdev->done);
|
|
}
|
|
|
|
static inline void irq_completion_init(struct mtk_snand_plat_dev *pdev)
|
|
{
|
|
init_completion(&pdev->done);
|
|
}
|
|
|
|
static inline int irq_completion_wait(struct mtk_snand_plat_dev *pdev,
|
|
void __iomem *reg, uint32_t bit,
|
|
uint32_t timeout_us)
|
|
{
|
|
int ret;
|
|
|
|
ret = wait_for_completion_timeout(&pdev->done,
|
|
usecs_to_jiffies(timeout_us));
|
|
if (!ret)
|
|
return -ETIMEDOUT;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* _MTK_SNAND_OS_H_ */
|