blob: 7aeec57cf604be69eff1161c0dcbea7ac95c0753 [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>
Furquan Shaikhc28984d2016-11-20 21:04:00 -080023#include <console/console.h>
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070024#include <spi_flash.h>
Julius Wernerec5e5e02014-08-20 15:29:56 -070025#include <symbols.h>
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -080026#include <cbmem.h>
Simon Glassaa58a9e2016-08-27 15:03:02 -060027#include <timer.h>
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070028
Aaron Durbinc6588c52015-05-15 13:15:34 -050029static struct spi_flash *spi_flash_info;
30
Simon Glassaa58a9e2016-08-27 15:03:02 -060031/*
32 * Set this to 1 to debug SPI speed, 0 to disable it
33 * The format is:
34 *
35 * read SPI 62854 7db7: 10416 us, 3089 KB/s, 24.712 Mbps
36 *
37 * The important number is the last one. It should roughly match your SPI
38 * clock. If it doesn't, your driver might need a little tuning.
39 */
40#define SPI_SPEED_DEBUG 0
41
Aaron Durbinc6588c52015-05-15 13:15:34 -050042static ssize_t spi_readat(const struct region_device *rd, void *b,
43 size_t offset, size_t size)
44{
Simon Glassaa58a9e2016-08-27 15:03:02 -060045 struct stopwatch sw;
46 bool show = SPI_SPEED_DEBUG && size >= 4 * KiB;
47
48 if (show)
49 stopwatch_init(&sw);
Furquan Shaikhc28984d2016-11-20 21:04:00 -080050 if (spi_flash_read(spi_flash_info, offset, size, b))
Aaron Durbinc6588c52015-05-15 13:15:34 -050051 return -1;
Simon Glassaa58a9e2016-08-27 15:03:02 -060052 if (show) {
53 long usecs;
54
55 usecs = stopwatch_duration_usecs(&sw);
56 u64 speed; /* KiB/s */
57 int bps; /* Bits per second */
58
59 speed = (u64)size * 1000 / usecs;
60 bps = speed * 8;
61
62 printk(BIOS_DEBUG, "read SPI %#zx %#zx: %ld us, %lld KB/s, %d.%03d Mbps\n",
63 offset, size, usecs, speed, bps / 1000, bps % 1000);
64 }
Aaron Durbinc6588c52015-05-15 13:15:34 -050065 return size;
66}
67
Aaron Durbin504b8f22016-08-11 11:10:42 -050068static ssize_t spi_writeat(const struct region_device *rd, const void *b,
69 size_t offset, size_t size)
70{
Furquan Shaikhc28984d2016-11-20 21:04:00 -080071 if (spi_flash_write(spi_flash_info, offset, size, b))
Aaron Durbin504b8f22016-08-11 11:10:42 -050072 return -1;
73 return size;
74}
75
76static ssize_t spi_eraseat(const struct region_device *rd,
77 size_t offset, size_t size)
78{
Furquan Shaikhc28984d2016-11-20 21:04:00 -080079 if (spi_flash_erase(spi_flash_info, offset, size))
Aaron Durbin504b8f22016-08-11 11:10:42 -050080 return -1;
81 return size;
82}
83
84/* Provide all operations on the same device. */
Aaron Durbinc6588c52015-05-15 13:15:34 -050085static const struct region_device_ops spi_ops = {
86 .mmap = mmap_helper_rdev_mmap,
87 .munmap = mmap_helper_rdev_munmap,
88 .readat = spi_readat,
Aaron Durbin504b8f22016-08-11 11:10:42 -050089 .writeat = spi_writeat,
90 .eraseat = spi_eraseat,
Vadim Bendeburyadcb0952014-05-01 12:23:09 -070091};
92
Aaron Durbinc6588c52015-05-15 13:15:34 -050093static struct mmap_helper_region_device mdev =
94 MMAP_HELPER_REGION_INIT(&spi_ops, 0, CONFIG_ROM_SIZE);
95
Julius Werner757943c2015-12-16 16:07:39 -080096static void switch_to_postram_cache(int unused)
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -080097{
Mary Ruthvena8aef3a2015-11-24 09:43:27 -080098 /*
99 * Call boot_device_init() to ensure spi_flash is initialized before
100 * backing mdev with postram cache. This prevents the mdev backing from
101 * being overwritten if spi_flash was not accessed before dram was up.
102 */
103 boot_device_init();
Julius Werner757943c2015-12-16 16:07:39 -0800104 if (_preram_cbfs_cache != _postram_cbfs_cache)
105 mmap_helper_device_init(&mdev, _postram_cbfs_cache,
106 _postram_cbfs_cache_size);
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -0800107}
Julius Werner757943c2015-12-16 16:07:39 -0800108ROMSTAGE_CBMEM_INIT_HOOK(switch_to_postram_cache);
Mary Ruthvenf82e8ab2015-11-13 14:05:27 -0800109
Aaron Durbinc6588c52015-05-15 13:15:34 -0500110void boot_device_init(void)
111{
Aaron Durbin08e842c2016-08-11 14:40:09 -0500112 int bus = CONFIG_BOOT_DEVICE_SPI_FLASH_BUS;
Aaron Durbinc6588c52015-05-15 13:15:34 -0500113 int cs = 0;
114
115 if (spi_flash_info != NULL)
116 return;
117
118 spi_flash_info = spi_flash_probe(bus, cs);
119
120 mmap_helper_device_init(&mdev, _cbfs_cache, _cbfs_cache_size);
121}
122
123/* Return the CBFS boot device. */
124const struct region_device *boot_device_ro(void)
125{
126 if (spi_flash_info == NULL)
127 return NULL;
128
129 return &mdev.rdev;
130}
Aaron Durbin504b8f22016-08-11 11:10:42 -0500131
132/* The read-only and read-write implementations are symmetric. */
133const struct region_device *boot_device_rw(void)
134{
135 return boot_device_ro();
136}