blob: 46e73463797a30874c1e1325285a5dfed34a9911 [file] [log] [blame]
Vadim Bendeburyadcb0952014-05-01 12:23:09 -07001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2014 Google Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070014 */
15
16/*
17 * This file provides a common CBFS wrapper for SPI storage. SPI driver
18 * context is expanded with the buffer descriptor used to store data read from
19 * SPI.
20 */
21
Aaron Durbinc6588c52015-05-15 13:15:34 -050022#include <boot_device.h>
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070023#include <spi_flash.h>
Julius Wernerec5e5e02014-08-20 15:29:56 -070024#include <symbols.h>
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -080025#include <cbmem.h>
Simon Glassaa58a9e2016-08-27 15:03:02 -060026#include <timer.h>
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070027
Aaron Durbinc6588c52015-05-15 13:15:34 -050028static struct spi_flash *spi_flash_info;
29
Simon Glassaa58a9e2016-08-27 15:03:02 -060030/*
31 * Set this to 1 to debug SPI speed, 0 to disable it
32 * The format is:
33 *
34 * read SPI 62854 7db7: 10416 us, 3089 KB/s, 24.712 Mbps
35 *
36 * The important number is the last one. It should roughly match your SPI
37 * clock. If it doesn't, your driver might need a little tuning.
38 */
39#define SPI_SPEED_DEBUG 0
40
Aaron Durbinc6588c52015-05-15 13:15:34 -050041static ssize_t spi_readat(const struct region_device *rd, void *b,
42 size_t offset, size_t size)
43{
Simon Glassaa58a9e2016-08-27 15:03:02 -060044 struct stopwatch sw;
45 bool show = SPI_SPEED_DEBUG && size >= 4 * KiB;
46
47 if (show)
48 stopwatch_init(&sw);
Aaron Durbinc6588c52015-05-15 13:15:34 -050049 if (spi_flash_info->read(spi_flash_info, offset, size, b))
50 return -1;
Simon Glassaa58a9e2016-08-27 15:03:02 -060051 if (show) {
52 long usecs;
53
54 usecs = stopwatch_duration_usecs(&sw);
55 u64 speed; /* KiB/s */
56 int bps; /* Bits per second */
57
58 speed = (u64)size * 1000 / usecs;
59 bps = speed * 8;
60
61 printk(BIOS_DEBUG, "read SPI %#zx %#zx: %ld us, %lld KB/s, %d.%03d Mbps\n",
62 offset, size, usecs, speed, bps / 1000, bps % 1000);
63 }
Aaron Durbinc6588c52015-05-15 13:15:34 -050064 return size;
65}
66
Aaron Durbin504b8f22016-08-11 11:10:42 -050067static ssize_t spi_writeat(const struct region_device *rd, const void *b,
68 size_t offset, size_t size)
69{
70 if (spi_flash_info->write(spi_flash_info, offset, size, b))
71 return -1;
72 return size;
73}
74
75static ssize_t spi_eraseat(const struct region_device *rd,
76 size_t offset, size_t size)
77{
78 if (spi_flash_info->erase(spi_flash_info, offset, size))
79 return -1;
80 return size;
81}
82
83/* Provide all operations on the same device. */
Aaron Durbinc6588c52015-05-15 13:15:34 -050084static const struct region_device_ops spi_ops = {
85 .mmap = mmap_helper_rdev_mmap,
86 .munmap = mmap_helper_rdev_munmap,
87 .readat = spi_readat,
Aaron Durbin504b8f22016-08-11 11:10:42 -050088 .writeat = spi_writeat,
89 .eraseat = spi_eraseat,
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070090};
91
Aaron Durbinc6588c52015-05-15 13:15:34 -050092static struct mmap_helper_region_device mdev =
93 MMAP_HELPER_REGION_INIT(&spi_ops, 0, CONFIG_ROM_SIZE);
94
Julius Werner757943c2015-12-16 16:07:39 -080095static void switch_to_postram_cache(int unused)
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -080096{
Mary Ruthvena8aef3a2015-11-24 09:43:27 -080097 /*
98 * Call boot_device_init() to ensure spi_flash is initialized before
99 * backing mdev with postram cache. This prevents the mdev backing from
100 * being overwritten if spi_flash was not accessed before dram was up.
101 */
102 boot_device_init();
Julius Werner757943c2015-12-16 16:07:39 -0800103 if (_preram_cbfs_cache != _postram_cbfs_cache)
104 mmap_helper_device_init(&mdev, _postram_cbfs_cache,
105 _postram_cbfs_cache_size);
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -0800106}
Julius Werner757943c2015-12-16 16:07:39 -0800107ROMSTAGE_CBMEM_INIT_HOOK(switch_to_postram_cache);
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -0800108
Aaron Durbinc6588c52015-05-15 13:15:34 -0500109void boot_device_init(void)
110{
Aaron Durbin08e842c2016-08-11 14:40:09 -0500111 int bus = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS;
Aaron Durbinc6588c52015-05-15 13:15:34 -0500112 int cs = 0;
113
114 if (spi_flash_info != NULL)
115 return;
116
117 spi_flash_info = spi_flash_probe(bus, cs);
118
119 mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
120}
121
122/* Return the CBFS boot device. */
123const struct region_device *boot_device_ro(void)
124{
125 if (spi_flash_info == NULL)
126 return NULL;
127
128 return &mdev.rdev;
129}
Aaron Durbin504b8f22016-08-11 11:10:42 -0500130
131/* The read-only and read-write implementations are symmetric. */
132const struct region_device *boot_device_rw(void)
133{
134 return boot_device_ro();
135}