AM335x 通过GPMC 与 FPGA 之间通信

AM335x 是一款A8的CPU ,其片上的资源是有限的,有时候我们需要外扩的功能有很多,比如 16个串口,4个LAN,IRIG,IO设备等。但是CPU 直接出来的 UART 和 LAN口不够用呀,这时候我们可以直接通过 am335x GPMC 总线上来扩展,如果还是不够用呢,那就需要FPGA 来译码达到更多的设备支持。

AM335X 上面有7个片选,我的设计将CS0 分给了 16个串口,CS3分给了IRIG 和 Nodeid. GPMC 总线上是支持 8bit 和 16 bit 模式的,正常情况下,如果选用8 bit , 那8位数据线一定是接到低8位的,否则读写错误是会出错的,如果选用16bit,要用到16位的数据线,一次读写可以进行读写2个字节的数据,这样就很方便。不过有时间我们引脚资源会很紧张,可能16位数据线上会被其他引脚给复用到,这时候我们就需要考虑到底如何配置才能在总线数据位不足的情况,正常读写呢?

下面这张图基本就将整个逻辑设计都讲清楚了

 

我们可以在 board-generic.c 中进行初始化配置总线的时序,然后注册 UART 设备,最后会与 8250的串口驱动进行匹配。

//------------------------------------------------------------------------------
//   += CS Setting
//------------------------------------------------------------------------------


// CS0 for TL16C752C
#define TL16C752C_UARTCLK               (14745600)

// CS0 A16/A15/A12/A9  4 address line --> 2^4=16 devices
#define CONFIG_TL16C752C_0_BASE  0x01000000
#define CONFIG_TL16C752C_1_BASE  0x01000200
#define CONFIG_TL16C752C_2_BASE  0x01001000
#define CONFIG_TL16C752C_3_BASE  0x01001200
#define CONFIG_TL16C752C_4_BASE  0x01008000
#define CONFIG_TL16C752C_5_BASE  0x01008200
#define CONFIG_TL16C752C_6_BASE  0x01009000
#define CONFIG_TL16C752C_7_BASE  0x01009200

#define CONFIG_TL16C752C_8_BASE  0x01010000
#define CONFIG_TL16C752C_9_BASE  0x01010200
#define CONFIG_TL16C752C_10_BASE 0x01011000
#define CONFIG_TL16C752C_11_BASE 0x01011200
#define CONFIG_TL16C752C_12_BASE 0x01018000
#define CONFIG_TL16C752C_13_BASE 0x01018200
#define CONFIG_TL16C752C_14_BASE 0x01019000
#define CONFIG_TL16C752C_15_BASE 0x01019200

static struct plat_serial8250_port tl16c752c_platform_data[] = {
        {
                .mapbase = CONFIG_TL16C752C_0_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_1_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_2_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_3_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_4_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_5_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_6_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_7_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },
        {
            .mapbase = CONFIG_TL16C752C_8_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_9_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_10_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_11_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_12_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_13_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_14_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {
            .mapbase = CONFIG_TL16C752C_15_BASE,
            .irqflags = IRQF_TRIGGER_HIGH,
            .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_SHARE_IRQ,
            .iotype = UPIO_MEM,
            .regshift = 6,
            .uartclk = TL16C752C_UARTCLK
        },

        {

        }
};

static struct platform_device tl16c752c_device = {
        .name = "serial8250",
        .id = PLAT8250_DEV_PLATFORM,
        .dev = {
                .platform_data = tl16c752c_platform_data,
        },
};

#define TL16C752C_SHARE_IRQ_GPIO                GPIO_TO_PIN(0, 2)

static struct gpio tl16c752c_uart_gpios[] __initdata = {
        { TL16C752C_SHARE_IRQ_GPIO, GPIOF_IN, "uart_irq" },
};

static int __init tl16c752c_uarts_init(void)
{
        int ret;

        ret = gpio_request_array(tl16c752c_uart_gpios, ARRAY_SIZE(tl16c752c_uart_gpios));
        if (ret < 0) {
                printk(KERN_ERR "Failed to request GPIO for UART IRQ\n");
                return -1;
        }

        tl16c752c_platform_data[0].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[1].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[2].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[3].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[4].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[5].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[6].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[7].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[8].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[9].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[10].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[11].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[12].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[13].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[14].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);
        tl16c752c_platform_data[15].irq = gpio_to_irq(TL16C752C_SHARE_IRQ_GPIO);

        platform_device_register(&tl16c752c_device);

        return 0;
}

// TL16C752C CS0 config
#define TL16C752C_GPMC_CONFIG1          0x00001000 //16 bit width
//#define TL16C752C_GPMC_CONFIG1                0x00000000 //8 bit width

// Configure GPMC registers for TL16C752D UART
static void gpmc_tl16c752c_config(void)
{
        struct gpmc_timings t;
        u32 tl16c752c_gpmc_config[6] = {0,};

        memset(&t, 0, sizeof(t));

        /* Read timings */
        t.cs_on = 0;
        t.adv_on = t.cs_on;
        t.adv_rd_off = 1;
        t.oe_on = t.adv_rd_off + 1;
        t.oe_off = t.oe_on + 6;
        t.cs_rd_off = t.oe_off + 2;
        t.access = t.cs_rd_off;
        t.rd_cycle = t.access + 1;

        /* Write timings */
        t.adv_wr_off = 1;
        t.we_on = t.adv_wr_off + 1;
        t.we_off = t.we_on + 6;
        t.cs_wr_off = t.we_off + 1;
        t.wr_cycle = t.cs_wr_off;

        // GPMC_CONFIG1
        tl16c752c_gpmc_config[0] = TL16C752C_GPMC_CONFIG1;

        // GPMC_CONFIG2 CS timing
        tl16c752c_gpmc_config[1] = t.cs_on | (t.cs_rd_off << 8) | (t.cs_wr_off << 16);

        // GPMC_CONFIG3 nADV / ALE timing
        tl16c752c_gpmc_config[2] = t.adv_on | (t.adv_rd_off << 8) | (t.adv_wr_off << 16);

        // GPMC_CONFIG4 nWE / nOE timing
        tl16c752c_gpmc_config[3] = t.oe_on | (t.oe_off << 8) | (t.we_on << 16) | (t.we_off << 24);

        // GPMC_CONFIG5 RdAccessTime / CycleTime timing
        tl16c752c_gpmc_config[4] = t.rd_cycle | (t.wr_cycle << 8) | (t.access << 16) | (t.page_burst_access << 24);

        // GPMC_CONFIG6 WrAccessTime / WrDataOnADmuxBus timing
        tl16c752c_gpmc_config[5] = (
                ( ((u32)1) << 0 )               // Bus turn around latency between successive accesses to the same CS (read to write) or to a different CS (read to read and read to write)
                | ( ((u32)1) << 6 )     // Add CYCLE2CYCLEDELAY between successive accesses to a different CS (any access type)
                | ( ((u32)1) << 7 )     // Add CYCLE2CYCLEDELAY between successive accesses to the same CS (any access type)
                | ( ((u32)4) << 8 )     // CYCLE2CYCLEDELAY Chip-select high pulse delay between successive accesses (0..15 clk)
                | ( ((u32)8) << 16 )    // WRDATAONADMUXBUS (1 clk after ADV off, at which address is latched)
                //| ( ((u32)1) << 24 )  // Write access time [clk 0..31] from start of cycle -> used as wait time in async mode
                );

        setup_gpmc_cs_config(tl16c752c_gpmc_config, 0, 0x01000000, GPMC_SIZE_16M);
}

 

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值