/* * Copyright (C) 2015 Jan Luebbe * * This file is part of barebox. * See file CREDITS for list of people who contributed to this project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define PINMUX0 0x01c40000 #define PINMUX1 0x01c40004 #define PINMUX1_I2C BIT(7) #define VDD3P3V_PWDN (0x01c40048) #include #define EMAC_BASE_ADDR 0x01C80000 #define EMAC_WRAPPER_BASE_ADDR 0x01C81000 #define EMAC_WRAPPER_RAM_ADDR 0x01C82000 #define EMAC_MDIO_BASE_ADDR 0x01C84000 static struct resource dm644x_emac_resources[] = { { .start = EMAC_BASE_ADDR, .end = EMAC_BASE_ADDR + 0xff, .flags = IORESOURCE_MEM, }, { .start = EMAC_WRAPPER_BASE_ADDR, .end = EMAC_WRAPPER_BASE_ADDR + 0xfff, .flags = IORESOURCE_MEM, }, { .start = EMAC_MDIO_BASE_ADDR, .end = EMAC_MDIO_BASE_ADDR + 0xff, .flags = IORESOURCE_MEM, }, { .start = EMAC_WRAPPER_RAM_ADDR, .end = EMAC_WRAPPER_RAM_ADDR + 0x1fff, /* 8kB */ .flags = IORESOURCE_MEM, } }; static struct davinci_emac_platform_data dm644x_emac_pdata = { .force_link = false, .interface_rmii = false, .phy_addr = 1, }; static struct device_d dm644x_emac_device = { .id = DEVICE_ID_DYNAMIC, .name = "davinci_emac", .num_resources = ARRAY_SIZE(dm644x_emac_resources), .resource = dm644x_emac_resources, .platform_data = &dm644x_emac_pdata, }; static void sysmobts_config_eeprom(const char *compatible) { struct device_node *node; node = of_find_node_by_path("/i2c/eeprom@50"); if (!node) { pr_err("can't find eeprom node to configure\n"); return; } of_set_property(node, "compatible", compatible, strlen(compatible) + 1, 1); of_device_enable(node); } static void sysmobts_board_detect(void) { int board_ver, board_cfg; char variant[4]; board_ver = gpio_get_value(15); board_ver |= gpio_get_value(16) << 1; board_ver |= gpio_get_value(17) << 2; board_cfg = gpio_get_value(10); board_cfg |= gpio_get_value(11) << 1; board_cfg |= gpio_get_value(12) << 3; board_cfg |= gpio_get_value(13) << 4; board_cfg |= gpio_get_value(14) << 5; variant[0] = 'A' + board_ver; variant[1] = '.'; variant[2] = '0' + board_cfg; variant[3] = '\0'; globalvar_add_simple("board.variant", variant); printf("detected 'sysmobts_v2 %s'\n", variant); /* enable the correct eeprom */ if (board_ver <= 2) { sysmobts_config_eeprom("24c02"); } else { sysmobts_config_eeprom("24c64"); } /* disable nand write protect */ if (board_ver >= 5) { gpio_direction_output(33, 1); udelay(100); } } static int sysmobts_set_ethaddr(void) { char addr[6]; int fd, ret; fd = open("/dev/eeprom0", O_RDONLY); if (fd < 0) { ret = fd; goto err; } ret = read_full(fd, addr, 6); if (ret < 0) goto err_open; eth_register_ethaddr(0, addr); ret = 0; err_open: close(fd); err: if (ret) pr_err("can't read eeprom /dev/eeprom0 (%s)\n", strerror(ret)); return ret; } #define MACH_TYPE_SYSMOBTS_V2 3758 static void sysmobts_devices_shutdown(void) { writel(readl(PINMUX1) | PINMUX1_I2C, PINMUX1); } static int sysmobts_coredevices_init(void) { board_shutdown = sysmobts_devices_shutdown; writel(0, VDD3P3V_PWDN); writel(0x8000000f, PINMUX0); writel(0x00050187, PINMUX1); writel(readl(PINMUX1) & ~PINMUX1_I2C, PINMUX1); sysmobts_board_detect(); return 0; } coredevice_initcall(sysmobts_coredevices_init); /* * taken from u-boot as cargo cult. It is best to match * the current behavior instead of trying to be smart and * see if this applies here or not. */ #define PSC_SILVER_BULLET (0x01c41a20) #define VBPR (0x20000020) static void davinci_errata_workarounds(void) { /* * Workaround for TMS320DM6446 errata 1.3.22: * PSC: PTSTAT Register Does Not Clear After Warm/Maximum Reset * Revision(s) Affected: 1.3 and earlier */ writel(0, PSC_SILVER_BULLET); /* * Set the PR_OLD_COUNT bits in the Bus Burst Priority Register (PBBPR) * as suggested in TMS320DM6446 errata 2.1.2: * * On DM6446 Silicon Revision 2.1 and earlier, under certain conditions * low priority modules can occupy the bus and prevent high priority * modules like the VPSS from getting the required DDR2 throughput. * A hex value of 0x20 should provide a good ARM (cache enabled) * performance and still allow good utilization by the VPSS or other * modules. */ writel(0x20, VBPR); } #define DAVINCI_PLLM (0x01C40910) /* PLL 1 Multiplier */ #define DAVINCI_AWCCR (0x01E00004) /* EMIF-A async wait cycle config register. */ #define DAVINCI_AWCCR_VAL (0x000000FF) /* EMIF-A async wait cycle config register value. */ #define DAVINCI_A2CR (0x01E00014) /* EMIF-A CS3 config register. */ #define DAVINCI_A2CR_VAL (0x00430491) /* EMIF-A CS3 value for FPGA. */ #define DAVINCI_A2CR_VAL8 (0x0063059D) /* EMIF-A CS3 value for FPGA. */ static int sysmobts_devices_init(void) { struct clk *dsp_clk; int ret; /* Configure AEMIF AWCCR */ writel(DAVINCI_AWCCR_VAL, DAVINCI_AWCCR); /* DM644X @ 594/297 MHz */ if ( (readl(DAVINCI_PLLM) & 0x0FF) < 22 ) { /* Configure AEMIF CS3 (fpga) */ writel(DAVINCI_A2CR_VAL, DAVINCI_A2CR); /* DM644X @ 810/405 MHz */ } else { /* Configure AEMIF CS3 (fpga) */ writel(DAVINCI_A2CR_VAL8, DAVINCI_A2CR); } davinci_errata_workarounds(); sysmobts_set_ethaddr(); platform_device_register(&dm644x_emac_device); defaultenv_append_directory(defaultenv_sysmobts); armlinux_set_architecture(MACH_TYPE_SYSMOBTS_V2); dsp_clk = clk_get(NULL, "dsp"); if (IS_ERR(dsp_clk)) { ret = PTR_ERR(dsp_clk); pr_err("unable to get DSP clock, err %d\n", ret); return 1; } ret = clk_enable(dsp_clk); if (ret < 0) { pr_err("unable to enable DSP clock, err %d\n", ret); return 1; } return 0; } device_initcall(sysmobts_devices_init);