aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/xilinx/brams.txt
blob: f1161114e9bb0cf40cb4d09977a69c9be29b6f2e (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
bram $__XILINX_RAMB36_SDP
  init 1
  abits 9
  dbits 72
  groups 2
  ports  1 1
  wrmode 0 1
  enable 1 8
  transp 0 0
  clocks 2 3
  clkpol 2 3
endbram

bram $__XILINX_RAMB18_SDP
  init 1
  abits 9
  dbits 36
  groups 2
  ports  1 1
  wrmode 0 1
  enable 1 4
  transp 0 0
  clocks 2 3
  clkpol 2 3
endbram

bram $__XILINX_RAMB36_TDP
  init 1
  abits 10     @a10d36
  dbits 36     @a10d36
  abits 11     @a11d18
  dbits 18     @a11d18
  abits 12     @a12d9
  dbits  9     @a12d9
  abits 13     @a13d4
  dbits  4     @a13d4
  abits 14     @a14d2
  dbits  2     @a14d2
  abits 15     @a15d1
  dbits  1     @a15d1
  groups 2
  ports  1 1
  wrmode 0 1
  enable 1 4   @a10d36
  enable 1 2   @a11d18
  enable 1 1   @a12d9 @a13d4 @a14d2 @a15d1
  transp 0 0
  clocks 2 3
  clkpol 2 3
endbram

bram $__XILINX_RAMB18_TDP
  init 1
  abits 10     @a10d18
  dbits 18     @a10d18
  abits 11     @a11d9
  dbits  9     @a11d9
  abits 12     @a12d4
  dbits  4     @a12d4
  abits 13     @a13d2
  dbits  2     @a13d2
  abits 14     @a14d1
  dbits  1     @a14d1
  groups 2
  ports  1 1
  wrmode 0 1
  enable 1 2   @a10d18
  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
  transp 0 0
  clocks 2 3
  clkpol 2 3
endbram

match $__XILINX_RAMB36_SDP
  min bits 4096
  min efficiency 5
  shuffle_enable B
  make_transp
  or_next_if_better
endmatch

match $__XILINX_RAMB18_SDP
  min bits 4096
  min efficiency 5
  shuffle_enable B
  make_transp
  or_next_if_better
endmatch

match $__XILINX_RAMB36_TDP
  min bits 4096
  min efficiency 5
  shuffle_enable B
  make_transp
  or_next_if_better
endmatch

match $__XILINX_RAMB18_TDP
  min bits 4096
  min efficiency 5
  shuffle_enable B
  make_transp
endmatch
ktick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -33,6 +33,8 @@
 #include <linux/magic.h>
 #include <linux/err.h>
 
+#define MTD_ERASE_PARTIAL	0x8000 /* partition only covers parts of an erase block */
+
 /* Our partition linked list */
 static LIST_HEAD(mtd_partitions);
 static DEFINE_MUTEX(mtd_partitions_mutex);
@@ -256,13 +258,60 @@ static int part_erase(struct mtd_info *m
 		return -EROFS;
 	if (instr->addr >= mtd->size)
 		return -EINVAL;
+
+	instr->partial_start = false;
+	if (mtd->flags & MTD_ERASE_PARTIAL) {
+		size_t readlen = 0;
+		u64 mtd_ofs;
+
+		instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
+		if (!instr->erase_buf)
+			return -ENOMEM;
+
+		mtd_ofs = part->offset + instr->addr;
+		instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
+
+		if (instr->erase_buf_ofs > 0) {
+			instr->addr -= instr->erase_buf_ofs;
+			ret = part->master->read(part->master,
+				instr->addr + part->offset,
+				part->master->erasesize,
+				&readlen, instr->erase_buf);
+
+			instr->partial_start = true;
+		} else {
+			mtd_ofs = part->offset + part->mtd.size;
+			instr->erase_buf_ofs = part->master->erasesize -
+				do_div(mtd_ofs, part->master->erasesize);
+
+			if (instr->erase_buf_ofs > 0) {
+				instr->len += instr->erase_buf_ofs;
+				ret = part->master->read(part->master,
+					part->offset + instr->addr +
+					instr->len - part->master->erasesize,
+					part->master->erasesize, &readlen,
+					instr->erase_buf);
+			} else {
+				ret = 0;
+			}
+		}
+		if (ret < 0) {
+			kfree(instr->erase_buf);
+			return ret;
+		}
+
+	}
+
 	instr->addr += part->offset;
 	ret = part->master->erase(part->master, instr);
 	if (ret) {
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 			instr->fail_addr -= part->offset;
 		instr->addr -= part->offset;
+		if (mtd->flags & MTD_ERASE_PARTIAL)
+			kfree(instr->erase_buf);
 	}
+
 	return ret;
 }
 
@@ -270,7 +319,25 @@ void mtd_erase_callback(struct erase_inf
 {
 	if (instr->mtd->erase == part_erase) {
 		struct mtd_part *part = PART(instr->mtd);
+		size_t wrlen = 0;
 
+		if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
+			if (instr->partial_start) {
+				part->master->write(part->master,
+					instr->addr, instr->erase_buf_ofs,
+					&wrlen, instr->erase_buf);
+				instr->addr += instr->erase_buf_ofs;
+			} else {
+				instr->len -= instr->erase_buf_ofs;
+				part->master->write(part->master,
+					instr->addr + instr->len,
+					instr->erase_buf_ofs, &wrlen,
+					instr->erase_buf +
+					part->master->erasesize -
+					instr->erase_buf_ofs);
+			}
+			kfree(instr->erase_buf);
+		}
 		if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
 			instr->fail_addr -= part->offset;
 		instr->addr -= part->offset;
@@ -529,18 +596,24 @@ static struct mtd_part *allocate_partiti
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
 	    mtd_mod_by_eb(slave->offset, &slave->mtd)) {
 		/* Doesn't start on a boundary of major erase size */
-		/* FIXME: Let it be writable if it is on a boundary of
-		 * _minor_ erase size though */
-		slave->mtd.flags &= ~MTD_WRITEABLE;
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
-			part->name);
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
+		if (((u32) slave->mtd.size) > master->erasesize)
+			slave->mtd.flags &= ~MTD_WRITEABLE;
+		else
+			slave->mtd.erasesize = slave->mtd.size;
 	}
 	if ((slave->mtd.flags & MTD_WRITEABLE) &&
-	    mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
-		slave->mtd.flags &= ~MTD_WRITEABLE;
-		printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
-			part->name);
+	    mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
+		slave->mtd.flags |= MTD_ERASE_PARTIAL;
+
+		if ((u32) slave->mtd.size > master->erasesize)
+			slave->mtd.flags &= ~MTD_WRITEABLE;
+		else
+			slave->mtd.erasesize = slave->mtd.size;
 	}
+	if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL)
+		printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n",
+				part->name);
 
 	slave->mtd.ecclayout = master->ecclayout;
 	if (master->block_isbad) {
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -57,6 +57,10 @@ struct erase_info {
 	u_long priv;
 	u_char state;
 	struct erase_info *next;
+
+	u8 *erase_buf;
+	u32 erase_buf_ofs;
+	bool partial_start;
 };
 
 struct mtd_erase_region_info {