Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/arch/arm/mach-orion5x/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 13 kB image not shown  

Quelle  ts78xx-setup.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * arch/arm/mach-orion5x/ts78xx-setup.c
 *
 * Maintainer: Alexander Clouter <alex@digriz.org.uk>
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysfs.h>
#include <linux/platform_device.h>
#include <linux/mv643xx_eth.h>
#include <linux/ata_platform.h>
#include <linux/mtd/platnand.h>
#include <linux/timeriomem-rng.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
#include "mpp.h"
#include "orion5x.h"
#include "ts78xx-fpga.h"

/*****************************************************************************
 * TS-78xx Info
 ****************************************************************************/


/*
 * FPGA - lives where the PCI bus would be at ORION5X_PCI_MEM_PHYS_BASE
 */

#define TS78XX_FPGA_REGS_PHYS_BASE 0xe8000000
#define TS78XX_FPGA_REGS_VIRT_BASE IOMEM(0xff900000)
#define TS78XX_FPGA_REGS_SIZE  SZ_1M

static struct ts78xx_fpga_data ts78xx_fpga = {
 .id  = 0,
 .state  = 1,
/* .supports = ... - populated by ts78xx_fpga_supports() */
};

/*****************************************************************************
 * I/O Address Mapping
 ****************************************************************************/

static struct map_desc ts78xx_io_desc[] __initdata = {
 {
  .virtual = (unsigned long)TS78XX_FPGA_REGS_VIRT_BASE,
  .pfn  = __phys_to_pfn(TS78XX_FPGA_REGS_PHYS_BASE),
  .length  = TS78XX_FPGA_REGS_SIZE,
  .type  = MT_DEVICE,
 },
};

static void __init ts78xx_map_io(void)
{
 orion5x_map_io();
 iotable_init(ts78xx_io_desc, ARRAY_SIZE(ts78xx_io_desc));
}

/*****************************************************************************
 * Ethernet
 ****************************************************************************/

static struct mv643xx_eth_platform_data ts78xx_eth_data = {
 .phy_addr = MV643XX_ETH_PHY_ADDR(0),
};

/*****************************************************************************
 * SATA
 ****************************************************************************/

static struct mv_sata_platform_data ts78xx_sata_data = {
 .n_ports = 2,
};

/*****************************************************************************
 * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
 ****************************************************************************/

#define TS_RTC_CTRL (TS78XX_FPGA_REGS_PHYS_BASE + 0x808)
#define TS_RTC_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x80c)

static struct resource ts78xx_ts_rtc_resources[] = {
 DEFINE_RES_MEM(TS_RTC_CTRL, 0x01),
 DEFINE_RES_MEM(TS_RTC_DATA, 0x01),
};

static struct platform_device ts78xx_ts_rtc_device = {
 .name  = "rtc-m48t86",
 .id  = -1,
 .resource = ts78xx_ts_rtc_resources,
 .num_resources  = ARRAY_SIZE(ts78xx_ts_rtc_resources),
};

static int ts78xx_ts_rtc_load(void)
{
 int rc;

 if (ts78xx_fpga.supports.ts_rtc.init == 0) {
  rc = platform_device_register(&ts78xx_ts_rtc_device);
  if (!rc)
   ts78xx_fpga.supports.ts_rtc.init = 1;
 } else {
  rc = platform_device_add(&ts78xx_ts_rtc_device);
 }

 if (rc)
  pr_info("RTC could not be registered: %d\n", rc);

 return rc;
}

static void ts78xx_ts_rtc_unload(void)
{
 platform_device_del(&ts78xx_ts_rtc_device);
}

/*****************************************************************************
 * NAND Flash
 ****************************************************************************/

#define TS_NAND_CTRL (TS78XX_FPGA_REGS_VIRT_BASE + 0x800) /* VIRT */
#define TS_NAND_DATA (TS78XX_FPGA_REGS_PHYS_BASE + 0x804) /* PHYS */

/*
 * hardware specific access to control-lines
 *
 * ctrl:
 * NAND_NCE: bit 0 -> bit 2
 * NAND_CLE: bit 1 -> bit 1
 * NAND_ALE: bit 2 -> bit 0
 */

static void ts78xx_ts_nand_cmd_ctrl(struct nand_chip *thisint cmd,
        unsigned int ctrl)
{
 if (ctrl & NAND_CTRL_CHANGE) {
  unsigned char bits;

  bits = (ctrl & NAND_NCE) << 2;
  bits |= ctrl & NAND_CLE;
  bits |= (ctrl & NAND_ALE) >> 2;

  writeb((readb(TS_NAND_CTRL) & ~0x7) | bits, TS_NAND_CTRL);
 }

 if (cmd != NAND_CMD_NONE)
  writeb(cmd, this->legacy.IO_ADDR_W);
}

static int ts78xx_ts_nand_dev_ready(struct nand_chip *chip)
{
 return readb(TS_NAND_CTRL) & 0x20;
}

static void ts78xx_ts_nand_write_buf(struct nand_chip *chip,
         const uint8_t *buf, int len)
{
 void __iomem *io_base = chip->legacy.IO_ADDR_W;
 unsigned long off = ((unsigned long)buf & 3);
 int sz;

 if (off) {
  sz = min_t(int, 4 - off, len);
  writesb(io_base, buf, sz);
  buf += sz;
  len -= sz;
 }

 sz = len >> 2;
 if (sz) {
  u32 *buf32 = (u32 *)buf;
  writesl(io_base, buf32, sz);
  buf += sz << 2;
  len -= sz << 2;
 }

 if (len)
  writesb(io_base, buf, len);
}

static void ts78xx_ts_nand_read_buf(struct nand_chip *chip,
        uint8_t *buf, int len)
{
 void __iomem *io_base = chip->legacy.IO_ADDR_R;
 unsigned long off = ((unsigned long)buf & 3);
 int sz;

 if (off) {
  sz = min_t(int, 4 - off, len);
  readsb(io_base, buf, sz);
  buf += sz;
  len -= sz;
 }

 sz = len >> 2;
 if (sz) {
  u32 *buf32 = (u32 *)buf;
  readsl(io_base, buf32, sz);
  buf += sz << 2;
  len -= sz << 2;
 }

 if (len)
  readsb(io_base, buf, len);
}

static struct mtd_partition ts78xx_ts_nand_parts[] = {
 {
  .name  = "mbr",
  .offset  = 0,
  .size  = SZ_128K,
  .mask_flags = MTD_WRITEABLE,
 }, {
  .name  = "kernel",
  .offset  = MTDPART_OFS_APPEND,
  .size  = SZ_4M,
 }, {
  .name  = "initrd",
  .offset  = MTDPART_OFS_APPEND,
  .size  = SZ_4M,
 }, {
  .name  = "rootfs",
  .offset  = MTDPART_OFS_APPEND,
  .size  = MTDPART_SIZ_FULL,
 }
};

static struct platform_nand_data ts78xx_ts_nand_data = {
 .chip = {
  .nr_chips  = 1,
  .partitions  = ts78xx_ts_nand_parts,
  .nr_partitions  = ARRAY_SIZE(ts78xx_ts_nand_parts),
  .chip_delay  = 15,
  .bbt_options  = NAND_BBT_USE_FLASH,
 },
 .ctrl = {
  /*
 * The HW ECC offloading functions, used to give about a 9%
 * performance increase for 'dd if=/dev/mtdblockX' and 5% for
 * nanddump.  This all however was changed by git commit
 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
 * no performance advantage to be had so we no longer bother
 */

  .cmd_ctrl  = ts78xx_ts_nand_cmd_ctrl,
  .dev_ready  = ts78xx_ts_nand_dev_ready,
  .write_buf  = ts78xx_ts_nand_write_buf,
  .read_buf  = ts78xx_ts_nand_read_buf,
 },
};

static struct resource ts78xx_ts_nand_resources
   = DEFINE_RES_MEM(TS_NAND_DATA, 4);

static struct platform_device ts78xx_ts_nand_device = {
 .name  = "gen_nand",
 .id  = -1,
 .dev  = {
  .platform_data = &ts78xx_ts_nand_data,
 },
 .resource = &ts78xx_ts_nand_resources,
 .num_resources = 1,
};

static int ts78xx_ts_nand_load(void)
{
 int rc;

 if (ts78xx_fpga.supports.ts_nand.init == 0) {
  rc = platform_device_register(&ts78xx_ts_nand_device);
  if (!rc)
   ts78xx_fpga.supports.ts_nand.init = 1;
 } else
  rc = platform_device_add(&ts78xx_ts_nand_device);

 if (rc)
  pr_info("NAND could not be registered: %d\n", rc);
 return rc;
};

static void ts78xx_ts_nand_unload(void)
{
 platform_device_del(&ts78xx_ts_nand_device);
}

/*****************************************************************************
 * HW RNG
 ****************************************************************************/

#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)

static struct resource ts78xx_ts_rng_resource
   = DEFINE_RES_MEM(TS_RNG_DATA, 4);

static struct timeriomem_rng_data ts78xx_ts_rng_data = {
 .period  = 1000000, /* one second */
};

static struct platform_device ts78xx_ts_rng_device = {
 .name  = "timeriomem_rng",
 .id  = -1,
 .dev  = {
  .platform_data = &ts78xx_ts_rng_data,
 },
 .resource = &ts78xx_ts_rng_resource,
 .num_resources = 1,
};

static int ts78xx_ts_rng_load(void)
{
 int rc;

 if (ts78xx_fpga.supports.ts_rng.init == 0) {
  rc = platform_device_register(&ts78xx_ts_rng_device);
  if (!rc)
   ts78xx_fpga.supports.ts_rng.init = 1;
 } else
  rc = platform_device_add(&ts78xx_ts_rng_device);

 if (rc)
  pr_info("RNG could not be registered: %d\n", rc);
 return rc;
};

static void ts78xx_ts_rng_unload(void)
{
 platform_device_del(&ts78xx_ts_rng_device);
}

/*****************************************************************************
 * FPGA 'hotplug' support code
 ****************************************************************************/

static void ts78xx_fpga_devices_zero_init(void)
{
 ts78xx_fpga.supports.ts_rtc.init = 0;
 ts78xx_fpga.supports.ts_nand.init = 0;
 ts78xx_fpga.supports.ts_rng.init = 0;
}

static void ts78xx_fpga_supports(void)
{
 /* TODO: put this 'table' into ts78xx-fpga.h */
 switch (ts78xx_fpga.id) {
 case TS7800_REV_1:
 case TS7800_REV_2:
 case TS7800_REV_3:
 case TS7800_REV_4:
 case TS7800_REV_5:
 case TS7800_REV_6:
 case TS7800_REV_7:
 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_warn("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)
{

 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 0;
}

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()
  : ts78xx_fpga_unload();

 if (!(ret < 0))
  ts78xx_fpga.state = value;

 return n;
}

static struct kobj_attribute ts78xx_fpga_attr =
 __ATTR(ts78xx_fpga, 0644, ts78xx_fpga_show, ts78xx_fpga_store);

/*****************************************************************************
 * General Setup
 ****************************************************************************/

static unsigned int ts78xx_mpp_modes[] __initdata = {
 MPP0_UNUSED,
 MPP1_GPIO,  /* JTAG Clock */
 MPP2_GPIO,  /* JTAG Data In */
 MPP3_GPIO,  /* Lat ECP2 256 FPGA - PB2B */
 MPP4_GPIO,  /* JTAG Data Out */
 MPP5_GPIO,  /* JTAG TMS */
 MPP6_GPIO,  /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
 MPP7_GPIO,  /* Lat ECP2 256 FPGA - PB22B */
 MPP8_UNUSED,
 MPP9_UNUSED,
 MPP10_UNUSED,
 MPP11_UNUSED,
 MPP12_UNUSED,
 MPP13_UNUSED,
 MPP14_UNUSED,
 MPP15_UNUSED,
 MPP16_UART,
 MPP17_UART,
 MPP18_UART,
 MPP19_UART,
 /*
 * MPP[20] PCI Clock Out 1
 * MPP[21] PCI Clock Out 0
 * MPP[22] Unused
 * MPP[23] Unused
 * MPP[24] Unused
 * MPP[25] Unused
 */

 0,
};

static void __init ts78xx_init(void)
{
 int ret;

 /*
 * Setup basic Orion functions. Need to be called early.
 */

 orion5x_init();

 orion5x_mpp_conf(ts78xx_mpp_modes);

 /*
 * Configure peripherals.
 */

 orion5x_ehci0_init();
 orion5x_ehci1_init();
 orion5x_eth_init(&ts78xx_eth_data);
 orion5x_sata_init(&ts78xx_sata_data);
 orion5x_uart0_init();
 orion5x_uart1_init();
 orion5x_xor_init();

 /* FPGA init */
 ts78xx_fpga_devices_zero_init();
 ret = ts78xx_fpga_load();
 ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
 if (ret)
  pr_err("sysfs_create_file failed: %d\n", ret);
}

MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
 /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
 .atag_offset = 0x100,
 .nr_irqs = ORION5X_NR_IRQS,
 .init_machine = ts78xx_init,
 .map_io  = ts78xx_map_io,
 .init_early = orion5x_init_early,
 .init_irq = orion5x_init_irq,
 .init_time = orion5x_timer_init,
 .restart = orion5x_restart,
MACHINE_END

Messung V0.5
C=90 H=92 G=90

¤ Dauer der Verarbeitung: 0.4 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.