Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Cobalt NOR flash functions
0004  *
0005  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
0006  *  All rights reserved.
0007  */
0008 
0009 #include <linux/mtd/mtd.h>
0010 #include <linux/mtd/map.h>
0011 #include <linux/mtd/cfi.h>
0012 #include <linux/time.h>
0013 
0014 #include "cobalt-flash.h"
0015 
0016 #define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset)
0017 
0018 static struct map_info cobalt_flash_map = {
0019     .name =     "cobalt-flash",
0020     .bankwidth =    2,         /* 16 bits */
0021     .size =     0x4000000, /* 64MB */
0022     .phys =     0,         /* offset  */
0023 };
0024 
0025 static map_word flash_read16(struct map_info *map, unsigned long offset)
0026 {
0027     map_word r;
0028 
0029     r.x[0] = cobalt_bus_read32(map->virt, ADRS(offset));
0030     if (offset & 0x2)
0031         r.x[0] >>= 16;
0032     else
0033         r.x[0] &= 0x0000ffff;
0034 
0035     return r;
0036 }
0037 
0038 static void flash_write16(struct map_info *map, const map_word datum,
0039               unsigned long offset)
0040 {
0041     u16 data = (u16)datum.x[0];
0042 
0043     cobalt_bus_write16(map->virt, ADRS(offset), data);
0044 }
0045 
0046 static void flash_copy_from(struct map_info *map, void *to,
0047                 unsigned long from, ssize_t len)
0048 {
0049     u32 src = from;
0050     u8 *dest = to;
0051     u32 data;
0052 
0053     while (len) {
0054         data = cobalt_bus_read32(map->virt, ADRS(src));
0055         do {
0056             *dest = data >> (8 * (src & 3));
0057             src++;
0058             dest++;
0059             len--;
0060         } while (len && (src % 4));
0061     }
0062 }
0063 
0064 static void flash_copy_to(struct map_info *map, unsigned long to,
0065               const void *from, ssize_t len)
0066 {
0067     const u8 *src = from;
0068     u32 dest = to;
0069 
0070     pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len);
0071     while (len) {
0072         u16 data;
0073 
0074         do {
0075             data = *src << (8 * (dest & 1));
0076             src++;
0077             dest++;
0078             len--;
0079         } while (len && (dest % 2));
0080 
0081         cobalt_bus_write16(map->virt, ADRS(dest - 2), data);
0082     }
0083 }
0084 
0085 int cobalt_flash_probe(struct cobalt *cobalt)
0086 {
0087     struct map_info *map = &cobalt_flash_map;
0088     struct mtd_info *mtd;
0089 
0090     BUG_ON(!map_bankwidth_supported(map->bankwidth));
0091     map->virt = cobalt->bar1;
0092     map->read = flash_read16;
0093     map->write = flash_write16;
0094     map->copy_from = flash_copy_from;
0095     map->copy_to = flash_copy_to;
0096 
0097     mtd = do_map_probe("cfi_probe", map);
0098     cobalt->mtd = mtd;
0099     if (!mtd) {
0100         cobalt_err("Probe CFI flash failed!\n");
0101         return -1;
0102     }
0103 
0104     mtd->owner = THIS_MODULE;
0105     mtd->dev.parent = &cobalt->pci_dev->dev;
0106     mtd_device_register(mtd, NULL, 0);
0107     return 0;
0108 }
0109 
0110 void cobalt_flash_remove(struct cobalt *cobalt)
0111 {
0112     if (cobalt->mtd) {
0113         mtd_device_unregister(cobalt->mtd);
0114         map_destroy(cobalt->mtd);
0115     }
0116 }