summaryrefslogtreecommitdiffstats
path: root/arch/mips/cavium-octeon/flash_setup.c
blob: 3395acde4d60accc3fc99193b79a9aeaa53505ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 *   Octeon Bootbus flash setup
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 2007, 2008 Cavium Networks
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/mtd/partitions.h>

#include <asm/octeon/octeon.h>

static struct map_info flash_map;
static struct mtd_info *mymtd;
static const char *part_probe_types[] = {
	"cmdlinepart",
#ifdef CONFIG_MTD_REDBOOT_PARTS
	"RedBoot",
#endif
	NULL
};

static map_word octeon_flash_map_read(struct map_info *map, unsigned long ofs)
{
	map_word r;

	down(&octeon_bootbus_sem);
	r = inline_map_read(map, ofs);
	up(&octeon_bootbus_sem);

	return r;
}

static void octeon_flash_map_write(struct map_info *map, const map_word datum,
				   unsigned long ofs)
{
	down(&octeon_bootbus_sem);
	inline_map_write(map, datum, ofs);
	up(&octeon_bootbus_sem);
}

static void octeon_flash_map_copy_from(struct map_info *map, void *to,
				       unsigned long from, ssize_t len)
{
	down(&octeon_bootbus_sem);
	inline_map_copy_from(map, to, from, len);
	up(&octeon_bootbus_sem);
}

static void octeon_flash_map_copy_to(struct map_info *map, unsigned long to,
				     const void *from, ssize_t len)
{
	down(&octeon_bootbus_sem);
	inline_map_copy_to(map, to, from, len);
	up(&octeon_bootbus_sem);
}

/*
 * Module/ driver initialization.
 *
 * Returns Zero on success
 */
static int octeon_flash_probe(struct platform_device *pdev)
{
	union cvmx_mio_boot_reg_cfgx region_cfg;
	u32 cs;
	int r;
	struct device_node *np = pdev->dev.of_node;

	r = of_property_read_u32(np, "reg", &cs);
	if (r)
		return r;

	/*
	 * Read the bootbus region 0 setup to determine the base
	 * address of the flash.
	 */
	region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs));
	if (region_cfg.s.en) {
		/*
		 * The bootloader always takes the flash and sets its
		 * address so the entire flash fits below
		 * 0x1fc00000. This way the flash aliases to
		 * 0x1fc00000 for booting. Software can access the
		 * full flash at the true address, while core boot can
		 * access 4MB.
		 */
		/* Use this name so old part lines work */
		flash_map.name = "phys_mapped_flash";
		flash_map.phys = region_cfg.s.base << 16;
		flash_map.size = 0x1fc00000 - flash_map.phys;
		/* 8-bit bus (0 + 1) or 16-bit bus (1 + 1) */
		flash_map.bankwidth = region_cfg.s.width + 1;
		flash_map.virt = ioremap(flash_map.phys, flash_map.size);
		pr_notice("Bootbus flash: Setting flash for %luMB flash at "
			  "0x%08llx\n", flash_map.size >> 20, flash_map.phys);
		WARN_ON(!map_bankwidth_supported(flash_map.bankwidth));
		flash_map.read = octeon_flash_map_read;
		flash_map.write = octeon_flash_map_write;
		flash_map.copy_from = octeon_flash_map_copy_from;
		flash_map.copy_to = octeon_flash_map_copy_to;
		mymtd = do_map_probe("cfi_probe", &flash_map);
		if (mymtd) {
			mymtd->owner = THIS_MODULE;
			mtd_device_parse_register(mymtd, part_probe_types,
						  NULL, NULL, 0);
		} else {
			pr_err("Failed to register MTD device for flash\n");
		}
	}
	return 0;
}

static const struct of_device_id of_flash_match[] = {
	{
		.compatible	= "cfi-flash",
	},
	{ },
};
MODULE_DEVICE_TABLE(of, of_flash_match);

static struct platform_driver of_flash_driver = {
	.driver = {
		.name = "octeon-of-flash",
		.of_match_table = of_flash_match,
	},
	.probe		= octeon_flash_probe,
};

static int octeon_flash_init(void)
{
	return platform_driver_register(&of_flash_driver);
}
late_initcall(octeon_flash_init);

MODULE_LICENSE("GPL");