]>
Commit | Line | Data |
---|---|---|
f37af276 AEK |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com> | |
4 | * | |
5 | * Authors: | |
6 | * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> | |
7 | */ | |
8 | ||
d678a59d | 9 | #include <common.h> |
f37af276 AEK |
10 | #include <dm.h> |
11 | #include <log.h> | |
12 | #include <mapmem.h> | |
13 | #include <asm/io.h> | |
14 | #include <linux/bitops.h> | |
15 | #include <linux/errno.h> | |
16 | #include "nvmxip.h" | |
17 | ||
f37af276 AEK |
18 | /** |
19 | * nvmxip_blk_read() - block device read operation | |
20 | * @dev: the block device | |
21 | * @blknr: first block number to read from | |
22 | * @blkcnt: number of blocks to read | |
23 | * @buffer: destination buffer | |
24 | * | |
25 | * Read data from the block storage device. | |
26 | * | |
27 | * Return: | |
28 | * | |
29 | * number of blocks read on success. Otherwise, failure | |
30 | */ | |
31 | static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, void *buffer) | |
32 | { | |
33 | struct nvmxip_plat *plat = dev_get_plat(dev->parent); | |
34 | struct blk_desc *desc = dev_get_uclass_plat(dev); | |
16be2bc7 MV |
35 | /* number of bytes to read */ |
36 | u32 size = blkcnt * desc->blksz; | |
f37af276 AEK |
37 | /* physical address of the first block to read */ |
38 | phys_addr_t blkaddr = plat->phys_base + blknr * desc->blksz; | |
16be2bc7 | 39 | void *virt_blkaddr; |
f37af276 AEK |
40 | uint qdata_idx; |
41 | ||
16be2bc7 | 42 | if (!buffer) |
f37af276 AEK |
43 | return -EINVAL; |
44 | ||
45 | log_debug("[%s]: reading from blknr: %lu , blkcnt: %lu\n", dev->name, blknr, blkcnt); | |
46 | ||
47 | virt_blkaddr = map_sysmem(blkaddr, 0); | |
48 | ||
49 | /* assumption: the data is virtually contiguous */ | |
50 | ||
16be2bc7 MV |
51 | #if IS_ENABLED(CONFIG_PHYS_64BIT) |
52 | for (qdata_idx = 0 ; qdata_idx < size; qdata_idx += sizeof(u64)) | |
53 | *(u64 *)(buffer + qdata_idx) = readq(virt_blkaddr + qdata_idx); | |
54 | #else | |
55 | for (qdata_idx = 0 ; qdata_idx < size; qdata_idx += sizeof(u32)) | |
56 | *(u32 *)(buffer + qdata_idx) = readl(virt_blkaddr + qdata_idx); | |
57 | #endif | |
f37af276 AEK |
58 | log_debug("[%s]: src[0]: 0x%llx , dst[0]: 0x%llx , src[-1]: 0x%llx , dst[-1]: 0x%llx\n", |
59 | dev->name, | |
16be2bc7 | 60 | *(u64 *)virt_blkaddr, |
f37af276 AEK |
61 | *(u64 *)buffer, |
62 | *(u64 *)((u8 *)virt_blkaddr + desc->blksz * blkcnt - sizeof(u64)), | |
63 | *(u64 *)((u8 *)buffer + desc->blksz * blkcnt - sizeof(u64))); | |
64 | ||
65 | unmap_sysmem(virt_blkaddr); | |
66 | ||
67 | return blkcnt; | |
68 | } | |
69 | ||
70 | /** | |
71 | * nvmxip_blk_probe() - block storage device probe | |
72 | * @dev: the block storage device | |
73 | * | |
74 | * Initialize the block storage descriptor. | |
75 | * | |
76 | * Return: | |
77 | * | |
78 | * Always return 0. | |
79 | */ | |
80 | static int nvmxip_blk_probe(struct udevice *dev) | |
81 | { | |
82 | struct nvmxip_plat *plat = dev_get_plat(dev->parent); | |
83 | struct blk_desc *desc = dev_get_uclass_plat(dev); | |
84 | ||
85 | desc->lba = plat->lba; | |
86 | desc->log2blksz = plat->lba_shift; | |
87 | desc->blksz = BIT(plat->lba_shift); | |
88 | desc->bdev = dev; | |
89 | ||
90 | log_debug("[%s]: block storage layout\n lbas: %lu , log2blksz: %d, blksz: %lu\n", | |
91 | dev->name, desc->lba, desc->log2blksz, desc->blksz); | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | static const struct blk_ops nvmxip_blk_ops = { | |
97 | .read = nvmxip_blk_read, | |
98 | }; | |
99 | ||
100 | U_BOOT_DRIVER(nvmxip_blk) = { | |
101 | .name = NVMXIP_BLKDRV_NAME, | |
102 | .id = UCLASS_BLK, | |
103 | .probe = nvmxip_blk_probe, | |
104 | .ops = &nvmxip_blk_ops, | |
105 | }; |