|
@@ -396,3 +396,143 @@ static void ts78xx_fpga_supports(void)
|
|
|
case TS7800_REV_8:
|
|
|
case TS7800_REV_9:
|
|
|
ts78xx_fpga.supports.ts_rtc.present = 1;
|
|
|
+ ts78xx_fpga.supports.ts_nand.present = 1;
|
|
|
+ ts78xx_fpga.supports.ts_rng.present = 1;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ /* enable devices if magic matches */
|
|
|
+ switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
|
|
|
+ case TS7800_FPGA_MAGIC:
|
|
|
+ pr_warning("unrecognised FPGA revision 0x%.2x\n",
|
|
|
+ ts78xx_fpga.id & 0xff);
|
|
|
+ ts78xx_fpga.supports.ts_rtc.present = 1;
|
|
|
+ ts78xx_fpga.supports.ts_nand.present = 1;
|
|
|
+ ts78xx_fpga.supports.ts_rng.present = 1;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ts78xx_fpga.supports.ts_rtc.present = 0;
|
|
|
+ ts78xx_fpga.supports.ts_nand.present = 0;
|
|
|
+ ts78xx_fpga.supports.ts_rng.present = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int ts78xx_fpga_load_devices(void)
|
|
|
+{
|
|
|
+ int tmp, ret = 0;
|
|
|
+
|
|
|
+ if (ts78xx_fpga.supports.ts_rtc.present == 1) {
|
|
|
+ tmp = ts78xx_ts_rtc_load();
|
|
|
+ if (tmp)
|
|
|
+ ts78xx_fpga.supports.ts_rtc.present = 0;
|
|
|
+ ret |= tmp;
|
|
|
+ }
|
|
|
+ if (ts78xx_fpga.supports.ts_nand.present == 1) {
|
|
|
+ tmp = ts78xx_ts_nand_load();
|
|
|
+ if (tmp)
|
|
|
+ ts78xx_fpga.supports.ts_nand.present = 0;
|
|
|
+ ret |= tmp;
|
|
|
+ }
|
|
|
+ if (ts78xx_fpga.supports.ts_rng.present == 1) {
|
|
|
+ tmp = ts78xx_ts_rng_load();
|
|
|
+ if (tmp)
|
|
|
+ ts78xx_fpga.supports.ts_rng.present = 0;
|
|
|
+ ret |= tmp;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int ts78xx_fpga_unload_devices(void)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (ts78xx_fpga.supports.ts_rtc.present == 1)
|
|
|
+ ts78xx_ts_rtc_unload();
|
|
|
+ if (ts78xx_fpga.supports.ts_nand.present == 1)
|
|
|
+ ts78xx_ts_nand_unload();
|
|
|
+ if (ts78xx_fpga.supports.ts_rng.present == 1)
|
|
|
+ ts78xx_ts_rng_unload();
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int ts78xx_fpga_load(void)
|
|
|
+{
|
|
|
+ ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
|
|
|
+
|
|
|
+ pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
|
|
|
+ (ts78xx_fpga.id >> 8) & 0xffffff,
|
|
|
+ ts78xx_fpga.id & 0xff);
|
|
|
+
|
|
|
+ ts78xx_fpga_supports();
|
|
|
+
|
|
|
+ if (ts78xx_fpga_load_devices()) {
|
|
|
+ ts78xx_fpga.state = -1;
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+static int ts78xx_fpga_unload(void)
|
|
|
+{
|
|
|
+ unsigned int fpga_id;
|
|
|
+
|
|
|
+ fpga_id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * There does not seem to be a feasible way to block access to the GPIO
|
|
|
+ * pins from userspace (/dev/mem). This if clause should hopefully warn
|
|
|
+ * those foolish enough not to follow 'policy' :)
|
|
|
+ *
|
|
|
+ * UrJTAG SVN since r1381 can be used to reprogram the FPGA
|
|
|
+ */
|
|
|
+ if (ts78xx_fpga.id != fpga_id) {
|
|
|
+ pr_err("FPGA magic/rev mismatch\n"
|
|
|
+ "TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
|
|
|
+ (ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
|
|
|
+ (fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
|
|
|
+ ts78xx_fpga.state = -1;
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ts78xx_fpga_unload_devices()) {
|
|
|
+ ts78xx_fpga.state = -1;
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+};
|
|
|
+
|
|
|
+static ssize_t ts78xx_fpga_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ if (ts78xx_fpga.state < 0)
|
|
|
+ return sprintf(buf, "borked\n");
|
|
|
+
|
|
|
+ return sprintf(buf, "%s\n", (ts78xx_fpga.state) ? "online" : "offline");
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t ts78xx_fpga_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, const char *buf, size_t n)
|
|
|
+{
|
|
|
+ int value, ret;
|
|
|
+
|
|
|
+ if (ts78xx_fpga.state < 0) {
|
|
|
+ pr_err("FPGA borked, you must powercycle ASAP\n");
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (strncmp(buf, "online", sizeof("online") - 1) == 0)
|
|
|
+ value = 1;
|
|
|
+ else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
|
|
|
+ value = 0;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (ts78xx_fpga.state == value)
|
|
|
+ return n;
|
|
|
+
|
|
|
+ ret = (ts78xx_fpga.state == 0)
|
|
|
+ ? ts78xx_fpga_load()
|