18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> et al. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/* Overhauled routines for dealing with different mmap regions of flash */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef __LINUX_MTD_MAP_H__ 98c2ecf20Sopenharmony_ci#define __LINUX_MTD_MAP_H__ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/bug.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 198c2ecf20Sopenharmony_ci#include <asm/barrier.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 228c2ecf20Sopenharmony_ci#define map_bankwidth(map) 1 238c2ecf20Sopenharmony_ci#define map_bankwidth_is_1(map) (map_bankwidth(map) == 1) 248c2ecf20Sopenharmony_ci#define map_bankwidth_is_large(map) (0) 258c2ecf20Sopenharmony_ci#define map_words(map) (1) 268c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 1 278c2ecf20Sopenharmony_ci#else 288c2ecf20Sopenharmony_ci#define map_bankwidth_is_1(map) (0) 298c2ecf20Sopenharmony_ci#endif 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 328c2ecf20Sopenharmony_ci# ifdef map_bankwidth 338c2ecf20Sopenharmony_ci# undef map_bankwidth 348c2ecf20Sopenharmony_ci# define map_bankwidth(map) ((map)->bankwidth) 358c2ecf20Sopenharmony_ci# else 368c2ecf20Sopenharmony_ci# define map_bankwidth(map) 2 378c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (0) 388c2ecf20Sopenharmony_ci# define map_words(map) (1) 398c2ecf20Sopenharmony_ci# endif 408c2ecf20Sopenharmony_ci#define map_bankwidth_is_2(map) (map_bankwidth(map) == 2) 418c2ecf20Sopenharmony_ci#undef MAX_MAP_BANKWIDTH 428c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 2 438c2ecf20Sopenharmony_ci#else 448c2ecf20Sopenharmony_ci#define map_bankwidth_is_2(map) (0) 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 488c2ecf20Sopenharmony_ci# ifdef map_bankwidth 498c2ecf20Sopenharmony_ci# undef map_bankwidth 508c2ecf20Sopenharmony_ci# define map_bankwidth(map) ((map)->bankwidth) 518c2ecf20Sopenharmony_ci# else 528c2ecf20Sopenharmony_ci# define map_bankwidth(map) 4 538c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (0) 548c2ecf20Sopenharmony_ci# define map_words(map) (1) 558c2ecf20Sopenharmony_ci# endif 568c2ecf20Sopenharmony_ci#define map_bankwidth_is_4(map) (map_bankwidth(map) == 4) 578c2ecf20Sopenharmony_ci#undef MAX_MAP_BANKWIDTH 588c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 4 598c2ecf20Sopenharmony_ci#else 608c2ecf20Sopenharmony_ci#define map_bankwidth_is_4(map) (0) 618c2ecf20Sopenharmony_ci#endif 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* ensure we never evaluate anything shorted than an unsigned long 648c2ecf20Sopenharmony_ci * to zero, and ensure we'll never miss the end of an comparison (bjd) */ 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1)) / sizeof(unsigned long)) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 698c2ecf20Sopenharmony_ci# ifdef map_bankwidth 708c2ecf20Sopenharmony_ci# undef map_bankwidth 718c2ecf20Sopenharmony_ci# define map_bankwidth(map) ((map)->bankwidth) 728c2ecf20Sopenharmony_ci# if BITS_PER_LONG < 64 738c2ecf20Sopenharmony_ci# undef map_bankwidth_is_large 748c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) 758c2ecf20Sopenharmony_ci# undef map_words 768c2ecf20Sopenharmony_ci# define map_words(map) map_calc_words(map) 778c2ecf20Sopenharmony_ci# endif 788c2ecf20Sopenharmony_ci# else 798c2ecf20Sopenharmony_ci# define map_bankwidth(map) 8 808c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (BITS_PER_LONG < 64) 818c2ecf20Sopenharmony_ci# define map_words(map) map_calc_words(map) 828c2ecf20Sopenharmony_ci# endif 838c2ecf20Sopenharmony_ci#define map_bankwidth_is_8(map) (map_bankwidth(map) == 8) 848c2ecf20Sopenharmony_ci#undef MAX_MAP_BANKWIDTH 858c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 8 868c2ecf20Sopenharmony_ci#else 878c2ecf20Sopenharmony_ci#define map_bankwidth_is_8(map) (0) 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 918c2ecf20Sopenharmony_ci# ifdef map_bankwidth 928c2ecf20Sopenharmony_ci# undef map_bankwidth 938c2ecf20Sopenharmony_ci# define map_bankwidth(map) ((map)->bankwidth) 948c2ecf20Sopenharmony_ci# undef map_bankwidth_is_large 958c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) 968c2ecf20Sopenharmony_ci# undef map_words 978c2ecf20Sopenharmony_ci# define map_words(map) map_calc_words(map) 988c2ecf20Sopenharmony_ci# else 998c2ecf20Sopenharmony_ci# define map_bankwidth(map) 16 1008c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (1) 1018c2ecf20Sopenharmony_ci# define map_words(map) map_calc_words(map) 1028c2ecf20Sopenharmony_ci# endif 1038c2ecf20Sopenharmony_ci#define map_bankwidth_is_16(map) (map_bankwidth(map) == 16) 1048c2ecf20Sopenharmony_ci#undef MAX_MAP_BANKWIDTH 1058c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 16 1068c2ecf20Sopenharmony_ci#else 1078c2ecf20Sopenharmony_ci#define map_bankwidth_is_16(map) (0) 1088c2ecf20Sopenharmony_ci#endif 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 1118c2ecf20Sopenharmony_ci/* always use indirect access for 256-bit to preserve kernel stack */ 1128c2ecf20Sopenharmony_ci# undef map_bankwidth 1138c2ecf20Sopenharmony_ci# define map_bankwidth(map) ((map)->bankwidth) 1148c2ecf20Sopenharmony_ci# undef map_bankwidth_is_large 1158c2ecf20Sopenharmony_ci# define map_bankwidth_is_large(map) (map_bankwidth(map) > BITS_PER_LONG/8) 1168c2ecf20Sopenharmony_ci# undef map_words 1178c2ecf20Sopenharmony_ci# define map_words(map) map_calc_words(map) 1188c2ecf20Sopenharmony_ci#define map_bankwidth_is_32(map) (map_bankwidth(map) == 32) 1198c2ecf20Sopenharmony_ci#undef MAX_MAP_BANKWIDTH 1208c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 32 1218c2ecf20Sopenharmony_ci#else 1228c2ecf20Sopenharmony_ci#define map_bankwidth_is_32(map) (0) 1238c2ecf20Sopenharmony_ci#endif 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#ifndef map_bankwidth 1268c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD 1278c2ecf20Sopenharmony_ci#warning "No CONFIG_MTD_MAP_BANK_WIDTH_xx selected. No NOR chip support can work" 1288c2ecf20Sopenharmony_ci#endif 1298c2ecf20Sopenharmony_cistatic inline int map_bankwidth(void *map) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci BUG(); 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci#define map_bankwidth_is_large(map) (0) 1358c2ecf20Sopenharmony_ci#define map_words(map) (0) 1368c2ecf20Sopenharmony_ci#define MAX_MAP_BANKWIDTH 1 1378c2ecf20Sopenharmony_ci#endif 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic inline int map_bankwidth_supported(int w) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci switch (w) { 1428c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_1 1438c2ecf20Sopenharmony_ci case 1: 1448c2ecf20Sopenharmony_ci#endif 1458c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_2 1468c2ecf20Sopenharmony_ci case 2: 1478c2ecf20Sopenharmony_ci#endif 1488c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_4 1498c2ecf20Sopenharmony_ci case 4: 1508c2ecf20Sopenharmony_ci#endif 1518c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8 1528c2ecf20Sopenharmony_ci case 8: 1538c2ecf20Sopenharmony_ci#endif 1548c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_16 1558c2ecf20Sopenharmony_ci case 16: 1568c2ecf20Sopenharmony_ci#endif 1578c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_MAP_BANK_WIDTH_32 1588c2ecf20Sopenharmony_ci case 32: 1598c2ecf20Sopenharmony_ci#endif 1608c2ecf20Sopenharmony_ci return 1; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci default: 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define MAX_MAP_LONGS (((MAX_MAP_BANKWIDTH * 8) + BITS_PER_LONG - 1) / BITS_PER_LONG) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_citypedef union { 1708c2ecf20Sopenharmony_ci unsigned long x[MAX_MAP_LONGS]; 1718c2ecf20Sopenharmony_ci} map_word; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* The map stuff is very simple. You fill in your struct map_info with 1748c2ecf20Sopenharmony_ci a handful of routines for accessing the device, making sure they handle 1758c2ecf20Sopenharmony_ci paging etc. correctly if your device needs it. Then you pass it off 1768c2ecf20Sopenharmony_ci to a chip probe routine -- either JEDEC or CFI probe or both -- via 1778c2ecf20Sopenharmony_ci do_map_probe(). If a chip is recognised, the probe code will invoke the 1788c2ecf20Sopenharmony_ci appropriate chip driver (if present) and return a struct mtd_info. 1798c2ecf20Sopenharmony_ci At which point, you fill in the mtd->module with your own module 1808c2ecf20Sopenharmony_ci address, and register it with the MTD core code. Or you could partition 1818c2ecf20Sopenharmony_ci it and register the partitions instead, or keep it for your own private 1828c2ecf20Sopenharmony_ci use; whatever. 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci The mtd->priv field will point to the struct map_info, and any further 1858c2ecf20Sopenharmony_ci private data required by the chip driver is linked from the 1868c2ecf20Sopenharmony_ci mtd->priv->fldrv_priv field. This allows the map driver to get at 1878c2ecf20Sopenharmony_ci the destructor function map->fldrv_destroy() when it's tired 1888c2ecf20Sopenharmony_ci of living. 1898c2ecf20Sopenharmony_ci*/ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistruct map_info { 1928c2ecf20Sopenharmony_ci const char *name; 1938c2ecf20Sopenharmony_ci unsigned long size; 1948c2ecf20Sopenharmony_ci resource_size_t phys; 1958c2ecf20Sopenharmony_ci#define NO_XIP (-1UL) 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci void __iomem *virt; 1988c2ecf20Sopenharmony_ci void *cached; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci int swap; /* this mapping's byte-swapping requirement */ 2018c2ecf20Sopenharmony_ci int bankwidth; /* in octets. This isn't necessarily the width 2028c2ecf20Sopenharmony_ci of actual bus cycles -- it's the repeat interval 2038c2ecf20Sopenharmony_ci in bytes, before you are talking to the first chip again. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_COMPLEX_MAPPINGS 2078c2ecf20Sopenharmony_ci map_word (*read)(struct map_info *, unsigned long); 2088c2ecf20Sopenharmony_ci void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci void (*write)(struct map_info *, const map_word, unsigned long); 2118c2ecf20Sopenharmony_ci void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* We can perhaps put in 'point' and 'unpoint' methods, if we really 2148c2ecf20Sopenharmony_ci want to enable XIP for non-linear mappings. Not yet though. */ 2158c2ecf20Sopenharmony_ci#endif 2168c2ecf20Sopenharmony_ci /* It's possible for the map driver to use cached memory in its 2178c2ecf20Sopenharmony_ci copy_from implementation (and _only_ with copy_from). However, 2188c2ecf20Sopenharmony_ci when the chip driver knows some flash area has changed contents, 2198c2ecf20Sopenharmony_ci it will signal it to the map driver through this routine to let 2208c2ecf20Sopenharmony_ci the map driver invalidate the corresponding cache as needed. 2218c2ecf20Sopenharmony_ci If there is no cache to care about this can be set to NULL. */ 2228c2ecf20Sopenharmony_ci void (*inval_cache)(struct map_info *, unsigned long, ssize_t); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* This will be called with 1 as parameter when the first map user 2258c2ecf20Sopenharmony_ci * needs VPP, and called with 0 when the last user exits. The map 2268c2ecf20Sopenharmony_ci * core maintains a reference counter, and assumes that VPP is a 2278c2ecf20Sopenharmony_ci * global resource applying to all mapped flash chips on the system. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci void (*set_vpp)(struct map_info *, int); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci unsigned long pfow_base; 2328c2ecf20Sopenharmony_ci unsigned long map_priv_1; 2338c2ecf20Sopenharmony_ci unsigned long map_priv_2; 2348c2ecf20Sopenharmony_ci struct device_node *device_node; 2358c2ecf20Sopenharmony_ci void *fldrv_priv; 2368c2ecf20Sopenharmony_ci struct mtd_chip_driver *fldrv; 2378c2ecf20Sopenharmony_ci}; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistruct mtd_chip_driver { 2408c2ecf20Sopenharmony_ci struct mtd_info *(*probe)(struct map_info *map); 2418c2ecf20Sopenharmony_ci void (*destroy)(struct mtd_info *); 2428c2ecf20Sopenharmony_ci struct module *module; 2438c2ecf20Sopenharmony_ci char *name; 2448c2ecf20Sopenharmony_ci struct list_head list; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_civoid register_mtd_chip_driver(struct mtd_chip_driver *); 2488c2ecf20Sopenharmony_civoid unregister_mtd_chip_driver(struct mtd_chip_driver *); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistruct mtd_info *do_map_probe(const char *name, struct map_info *map); 2518c2ecf20Sopenharmony_civoid map_destroy(struct mtd_info *mtd); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci#define ENABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 1); } while (0) 2548c2ecf20Sopenharmony_ci#define DISABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 0); } while (0) 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci#define INVALIDATE_CACHED_RANGE(map, from, size) \ 2578c2ecf20Sopenharmony_ci do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0) 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define map_word_equal(map, val1, val2) \ 2608c2ecf20Sopenharmony_ci({ \ 2618c2ecf20Sopenharmony_ci int i, ret = 1; \ 2628c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) \ 2638c2ecf20Sopenharmony_ci if ((val1).x[i] != (val2).x[i]) { \ 2648c2ecf20Sopenharmony_ci ret = 0; \ 2658c2ecf20Sopenharmony_ci break; \ 2668c2ecf20Sopenharmony_ci } \ 2678c2ecf20Sopenharmony_ci ret; \ 2688c2ecf20Sopenharmony_ci}) 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci#define map_word_and(map, val1, val2) \ 2718c2ecf20Sopenharmony_ci({ \ 2728c2ecf20Sopenharmony_ci map_word r; \ 2738c2ecf20Sopenharmony_ci int i; \ 2748c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) \ 2758c2ecf20Sopenharmony_ci r.x[i] = (val1).x[i] & (val2).x[i]; \ 2768c2ecf20Sopenharmony_ci r; \ 2778c2ecf20Sopenharmony_ci}) 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#define map_word_clr(map, val1, val2) \ 2808c2ecf20Sopenharmony_ci({ \ 2818c2ecf20Sopenharmony_ci map_word r; \ 2828c2ecf20Sopenharmony_ci int i; \ 2838c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) \ 2848c2ecf20Sopenharmony_ci r.x[i] = (val1).x[i] & ~(val2).x[i]; \ 2858c2ecf20Sopenharmony_ci r; \ 2868c2ecf20Sopenharmony_ci}) 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#define map_word_or(map, val1, val2) \ 2898c2ecf20Sopenharmony_ci({ \ 2908c2ecf20Sopenharmony_ci map_word r; \ 2918c2ecf20Sopenharmony_ci int i; \ 2928c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) \ 2938c2ecf20Sopenharmony_ci r.x[i] = (val1).x[i] | (val2).x[i]; \ 2948c2ecf20Sopenharmony_ci r; \ 2958c2ecf20Sopenharmony_ci}) 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci#define map_word_andequal(map, val1, val2, val3) \ 2988c2ecf20Sopenharmony_ci({ \ 2998c2ecf20Sopenharmony_ci int i, ret = 1; \ 3008c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) { \ 3018c2ecf20Sopenharmony_ci if (((val1).x[i] & (val2).x[i]) != (val3).x[i]) { \ 3028c2ecf20Sopenharmony_ci ret = 0; \ 3038c2ecf20Sopenharmony_ci break; \ 3048c2ecf20Sopenharmony_ci } \ 3058c2ecf20Sopenharmony_ci } \ 3068c2ecf20Sopenharmony_ci ret; \ 3078c2ecf20Sopenharmony_ci}) 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define map_word_bitsset(map, val1, val2) \ 3108c2ecf20Sopenharmony_ci({ \ 3118c2ecf20Sopenharmony_ci int i, ret = 0; \ 3128c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) { \ 3138c2ecf20Sopenharmony_ci if ((val1).x[i] & (val2).x[i]) { \ 3148c2ecf20Sopenharmony_ci ret = 1; \ 3158c2ecf20Sopenharmony_ci break; \ 3168c2ecf20Sopenharmony_ci } \ 3178c2ecf20Sopenharmony_ci } \ 3188c2ecf20Sopenharmony_ci ret; \ 3198c2ecf20Sopenharmony_ci}) 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic inline map_word map_word_load(struct map_info *map, const void *ptr) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci map_word r; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (map_bankwidth_is_1(map)) 3268c2ecf20Sopenharmony_ci r.x[0] = *(unsigned char *)ptr; 3278c2ecf20Sopenharmony_ci else if (map_bankwidth_is_2(map)) 3288c2ecf20Sopenharmony_ci r.x[0] = get_unaligned((uint16_t *)ptr); 3298c2ecf20Sopenharmony_ci else if (map_bankwidth_is_4(map)) 3308c2ecf20Sopenharmony_ci r.x[0] = get_unaligned((uint32_t *)ptr); 3318c2ecf20Sopenharmony_ci#if BITS_PER_LONG >= 64 3328c2ecf20Sopenharmony_ci else if (map_bankwidth_is_8(map)) 3338c2ecf20Sopenharmony_ci r.x[0] = get_unaligned((uint64_t *)ptr); 3348c2ecf20Sopenharmony_ci#endif 3358c2ecf20Sopenharmony_ci else if (map_bankwidth_is_large(map)) 3368c2ecf20Sopenharmony_ci memcpy(r.x, ptr, map->bankwidth); 3378c2ecf20Sopenharmony_ci else 3388c2ecf20Sopenharmony_ci BUG(); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return r; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic inline map_word map_word_load_partial(struct map_info *map, map_word orig, const unsigned char *buf, int start, int len) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int i; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (map_bankwidth_is_large(map)) { 3488c2ecf20Sopenharmony_ci char *dest = (char *)&orig; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci memcpy(dest+start, buf, len); 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci for (i = start; i < start+len; i++) { 3538c2ecf20Sopenharmony_ci int bitpos; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN 3568c2ecf20Sopenharmony_ci bitpos = i * 8; 3578c2ecf20Sopenharmony_ci#else /* __BIG_ENDIAN */ 3588c2ecf20Sopenharmony_ci bitpos = (map_bankwidth(map) - 1 - i) * 8; 3598c2ecf20Sopenharmony_ci#endif 3608c2ecf20Sopenharmony_ci orig.x[0] &= ~(0xff << bitpos); 3618c2ecf20Sopenharmony_ci orig.x[0] |= (unsigned long)buf[i-start] << bitpos; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci return orig; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci#if BITS_PER_LONG < 64 3688c2ecf20Sopenharmony_ci#define MAP_FF_LIMIT 4 3698c2ecf20Sopenharmony_ci#else 3708c2ecf20Sopenharmony_ci#define MAP_FF_LIMIT 8 3718c2ecf20Sopenharmony_ci#endif 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic inline map_word map_word_ff(struct map_info *map) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci map_word r; 3768c2ecf20Sopenharmony_ci int i; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (map_bankwidth(map) < MAP_FF_LIMIT) { 3798c2ecf20Sopenharmony_ci int bw = 8 * map_bankwidth(map); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci r.x[0] = (1UL << bw) - 1; 3828c2ecf20Sopenharmony_ci } else { 3838c2ecf20Sopenharmony_ci for (i = 0; i < map_words(map); i++) 3848c2ecf20Sopenharmony_ci r.x[i] = ~0UL; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci return r; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic inline map_word inline_map_read(struct map_info *map, unsigned long ofs) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci map_word r; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (map_bankwidth_is_1(map)) 3948c2ecf20Sopenharmony_ci r.x[0] = __raw_readb(map->virt + ofs); 3958c2ecf20Sopenharmony_ci else if (map_bankwidth_is_2(map)) 3968c2ecf20Sopenharmony_ci r.x[0] = __raw_readw(map->virt + ofs); 3978c2ecf20Sopenharmony_ci else if (map_bankwidth_is_4(map)) 3988c2ecf20Sopenharmony_ci r.x[0] = __raw_readl(map->virt + ofs); 3998c2ecf20Sopenharmony_ci#if BITS_PER_LONG >= 64 4008c2ecf20Sopenharmony_ci else if (map_bankwidth_is_8(map)) 4018c2ecf20Sopenharmony_ci r.x[0] = __raw_readq(map->virt + ofs); 4028c2ecf20Sopenharmony_ci#endif 4038c2ecf20Sopenharmony_ci else if (map_bankwidth_is_large(map)) 4048c2ecf20Sopenharmony_ci memcpy_fromio(r.x, map->virt + ofs, map->bankwidth); 4058c2ecf20Sopenharmony_ci else 4068c2ecf20Sopenharmony_ci BUG(); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return r; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic inline void inline_map_write(struct map_info *map, const map_word datum, unsigned long ofs) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci if (map_bankwidth_is_1(map)) 4148c2ecf20Sopenharmony_ci __raw_writeb(datum.x[0], map->virt + ofs); 4158c2ecf20Sopenharmony_ci else if (map_bankwidth_is_2(map)) 4168c2ecf20Sopenharmony_ci __raw_writew(datum.x[0], map->virt + ofs); 4178c2ecf20Sopenharmony_ci else if (map_bankwidth_is_4(map)) 4188c2ecf20Sopenharmony_ci __raw_writel(datum.x[0], map->virt + ofs); 4198c2ecf20Sopenharmony_ci#if BITS_PER_LONG >= 64 4208c2ecf20Sopenharmony_ci else if (map_bankwidth_is_8(map)) 4218c2ecf20Sopenharmony_ci __raw_writeq(datum.x[0], map->virt + ofs); 4228c2ecf20Sopenharmony_ci#endif 4238c2ecf20Sopenharmony_ci else if (map_bankwidth_is_large(map)) 4248c2ecf20Sopenharmony_ci memcpy_toio(map->virt+ofs, datum.x, map->bankwidth); 4258c2ecf20Sopenharmony_ci else 4268c2ecf20Sopenharmony_ci BUG(); 4278c2ecf20Sopenharmony_ci mb(); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic inline void inline_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci if (map->cached) 4338c2ecf20Sopenharmony_ci memcpy(to, (char *)map->cached + from, len); 4348c2ecf20Sopenharmony_ci else 4358c2ecf20Sopenharmony_ci memcpy_fromio(to, map->virt + from, len); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic inline void inline_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci memcpy_toio(map->virt + to, from, len); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_COMPLEX_MAPPINGS 4448c2ecf20Sopenharmony_ci#define map_read(map, ofs) (map)->read(map, ofs) 4458c2ecf20Sopenharmony_ci#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) 4468c2ecf20Sopenharmony_ci#define map_write(map, datum, ofs) (map)->write(map, datum, ofs) 4478c2ecf20Sopenharmony_ci#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciextern void simple_map_init(struct map_info *); 4508c2ecf20Sopenharmony_ci#define map_is_linear(map) (map->phys != NO_XIP) 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#else 4538c2ecf20Sopenharmony_ci#define map_read(map, ofs) inline_map_read(map, ofs) 4548c2ecf20Sopenharmony_ci#define map_copy_from(map, to, from, len) inline_map_copy_from(map, to, from, len) 4558c2ecf20Sopenharmony_ci#define map_write(map, datum, ofs) inline_map_write(map, datum, ofs) 4568c2ecf20Sopenharmony_ci#define map_copy_to(map, to, from, len) inline_map_copy_to(map, to, from, len) 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) 4608c2ecf20Sopenharmony_ci#define map_is_linear(map) ({ (void)(map); 1; }) 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci#endif /* __LINUX_MTD_MAP_H__ */ 465