From a0e6fe60f5a4dfb3401259803e74312f19398453 Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Tue, 17 Mar 2009 16:34:39 +0100 Subject: linux-davinci: add 2.6.28 --- .../0001-USB-musb-cppi-bugfixes.patch | 72 + ...2-ARM-Mark-unsupported-syscalls-as-IGNORE.patch | 31 + .../0003-Add-macros-for-enabling-a-UART.patch | 29 + ...able-MAC-address-to-be-specified-on-kerne.patch | 54 + ...dd-DAS-Mini-DAS-and-AFE-USB-machine-types.patch | 135 ++ ...ASoC-DaVinci-Fix-SFFSDR-compilation-error.patch | 65 + ...C-Davinci-Fix-SFFSDR-FPGA-module-codec-FS.patch | 57 + ...oC-Davinci-Fix-incorrect-machine-type-for.patch | 26 + ...ound-ASoC-Fix-DaVinci-module-unload-error.patch | 54 + ...-Add-generic-FPGA-bitstream-loader-driver.patch | 1512 ++++++++++++++++++++ ...rvpss-example-driver-for-the-SFFSDR-board.patch | 919 ++++++++++++ ...FFSDR-to-support-FPGA-and-lyrvpss-drivers.patch | 934 ++++++++++++ .../linux-davinci-2.6.28/davinci-sffsdr/defconfig | 1106 ++++++++++++++ packages/linux/linux-davinci_2.6.28.bb | 28 + 14 files changed, 5022 insertions(+) create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0001-USB-musb-cppi-bugfixes.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0002-ARM-Mark-unsupported-syscalls-as-IGNORE.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0003-Add-macros-for-enabling-a-UART.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0004-Davinci-Enable-MAC-address-to-be-specified-on-kerne.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0005-Add-DAS-Mini-DAS-and-AFE-USB-machine-types.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0006-ALSA-ASoC-DaVinci-Fix-SFFSDR-compilation-error.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0007-ALSA-ASoC-Davinci-Fix-SFFSDR-FPGA-module-codec-FS.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0008-ALSA-ASoC-Davinci-Fix-incorrect-machine-type-for.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0009-sound-ASoC-Fix-DaVinci-module-unload-error.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0011-Add-lyrvpss-example-driver-for-the-SFFSDR-board.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0012-Update-SFFSDR-to-support-FPGA-and-lyrvpss-drivers.patch create mode 100644 packages/linux/linux-davinci-2.6.28/davinci-sffsdr/defconfig create mode 100644 packages/linux/linux-davinci_2.6.28.bb (limited to 'packages/linux') diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0001-USB-musb-cppi-bugfixes.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0001-USB-musb-cppi-bugfixes.patch new file mode 100644 index 0000000000..ad6a19b3d6 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0001-USB-musb-cppi-bugfixes.patch @@ -0,0 +1,72 @@ +From 901b05b33b8ca924bab3fa63ef3fd6dcb123e318 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Sat, 24 Jan 2009 17:57:30 -0800 +Subject: [PATCH 01/12] USB: musb cppi bugfixes + +These compilation errors are related to incorrect +debugging macro and variable names and generated the +following errors: + + drivers/usb/musb/cppi_dma.c:437:5: warning: "MUSB_DEBUG" is not defined + drivers/usb/musb/cppi_dma.c: In function 'cppi_next_rx_segment': + drivers/usb/musb/cppi_dma.c:884: error: 'debug' undeclared (first use in this function) + +Signed-off-by: Hugo Villeneuve +Signed-off-by: David Brownell +Signed-off-by: Greg Kroah-Hartman +--- + drivers/usb/musb/cppi_dma.c | 9 +++++++-- + 1 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c +index 5ad6d08..d8d5345 100644 +--- a/drivers/usb/musb/cppi_dma.c ++++ b/drivers/usb/musb/cppi_dma.c +@@ -9,6 +9,7 @@ + #include + + #include "musb_core.h" ++#include "musb_debug.h" + #include "cppi_dma.h" + + +@@ -423,6 +424,7 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx, + } + } + ++#ifdef CONFIG_USB_MUSB_DEBUG + static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) + { + pr_debug("RXBD/%s %08x: " +@@ -431,10 +433,11 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd) + bd->hw_next, bd->hw_bufp, bd->hw_off_len, + bd->hw_options); + } ++#endif + + static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx) + { +-#if MUSB_DEBUG > 0 ++#ifdef CONFIG_USB_MUSB_DEBUG + struct cppi_descriptor *bd; + + if (!_dbg_level(level)) +@@ -881,12 +884,14 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket) + bd->hw_options |= CPPI_SOP_SET; + tail->hw_options |= CPPI_EOP_SET; + +- if (debug >= 5) { ++#ifdef CONFIG_USB_MUSB_DEBUG ++ if (_dbg_level(5)) { + struct cppi_descriptor *d; + + for (d = rx->head; d; d = d->next) + cppi_dump_rxbd("S", d); + } ++#endif + + /* in case the preceding transfer left some state... */ + tail = rx->last_processed; +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0002-ARM-Mark-unsupported-syscalls-as-IGNORE.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0002-ARM-Mark-unsupported-syscalls-as-IGNORE.patch new file mode 100644 index 0000000000..b569d5d535 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0002-ARM-Mark-unsupported-syscalls-as-IGNORE.patch @@ -0,0 +1,31 @@ +From f090919d8c0d1ecb0df6148ff34b6c20d4fb4ba3 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 14:35:56 -0500 +Subject: [PATCH 02/12] ARM: Mark unsupported syscalls as IGNORE + +Signed-off-by: Hugo Villeneuve +--- + scripts/checksyscalls.sh | 7 +++++++ + 1 files changed, 7 insertions(+), 0 deletions(-) + +diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh +index 60d00d1..2a75819 100755 +--- a/scripts/checksyscalls.sh ++++ b/scripts/checksyscalls.sh +@@ -109,6 +109,13 @@ cat << EOF + #define __IGNORE_getpmsg + #define __IGNORE_putpmsg + #define __IGNORE_vserver ++ ++/* Remove some warnings for ARM target. */ ++#define __IGNORE_fadvise64 ++#define __IGNORE_migrate_pages ++#define __IGNORE_pselect6 ++#define __IGNORE_ppoll ++#define __IGNORE_epoll_pwait + EOF + } + +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0003-Add-macros-for-enabling-a-UART.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0003-Add-macros-for-enabling-a-UART.patch new file mode 100644 index 0000000000..9ca9f020e9 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0003-Add-macros-for-enabling-a-UART.patch @@ -0,0 +1,29 @@ +From 33beaeec0dfec8cc5bf7a88f524a2a1f41fa30ba Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 14:45:19 -0500 +Subject: [PATCH 03/12] Add macros for enabling a UART + +Signed-off-by: Hugo Villeneuve +--- + arch/arm/mach-davinci/include/mach/serial.h | 5 +++++ + 1 files changed, 5 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-davinci/include/mach/serial.h b/arch/arm/mach-davinci/include/mach/serial.h +index de7c667..d77d25b 100644 +--- a/arch/arm/mach-davinci/include/mach/serial.h ++++ b/arch/arm/mach-davinci/include/mach/serial.h +@@ -30,6 +30,11 @@ struct davinci_uart_config { + unsigned int enabled_uarts; + }; + ++/* Use these macros in board setup code to enable a specific UART. */ ++#define DAVINCI_UART0_ENA (1 << 0) ++#define DAVINCI_UART1_ENA (1 << 1) ++#define DAVINCI_UART2_ENA (1 << 2) ++ + extern void davinci_serial_init(struct davinci_uart_config *); + + #endif /* __ASM_ARCH_SERIAL_H */ +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0004-Davinci-Enable-MAC-address-to-be-specified-on-kerne.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0004-Davinci-Enable-MAC-address-to-be-specified-on-kerne.patch new file mode 100644 index 0000000000..d1721914c6 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0004-Davinci-Enable-MAC-address-to-be-specified-on-kerne.patch @@ -0,0 +1,54 @@ +From 2e852db8367da3d3f60230419bd36bab2535c0ff Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 17:11:05 -0500 +Subject: [PATCH 04/12] Davinci: Enable MAC address to be specified on kernel cmd line + +Signed-off-by: Hugo Villeneuve +--- + arch/arm/mach-davinci/devices.c | 23 +++++++++++++++++++++++ + 1 files changed, 23 insertions(+), 0 deletions(-) + +diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c +index a0f5a60..db433be 100644 +--- a/arch/arm/mach-davinci/devices.c ++++ b/arch/arm/mach-davinci/devices.c +@@ -353,6 +353,27 @@ static struct platform_device dm646x_emac_device = { + } + }; + ++/* Get Ethernet address from kernel boot params */ ++static u8 davinci_bootloader_mac_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; ++ ++static int /*__init */ davinci_bootloader_mac_setup(char *str) ++{ ++ int i; ++ ++ if (str == NULL) ++ return 0; ++ ++ /* Conversion of a MAC address from a string (AA:BB:CC:DD:EE:FF) ++ * to a 6 bytes array. */ ++ for (i = 0; i < 6; i++) ++ davinci_bootloader_mac_addr[i] = ++ simple_strtol(&str[i*3], (char **)NULL, 16); ++ ++ return 1; ++} ++/* Get MAC address from kernel boot parameter eth=AA:BB:CC:DD:EE:FF */ ++__setup("eth=", davinci_bootloader_mac_setup); ++ + void davinci_init_emac(char *mac_addr) + { + DECLARE_MAC_BUF(buf); +@@ -366,6 +387,8 @@ void davinci_init_emac(char *mac_addr) + + if (mac_addr && is_valid_ether_addr(mac_addr)) + memcpy(emac_pdata.mac_addr, mac_addr, 6); ++ else if (is_valid_ether_addr(davinci_bootloader_mac_addr)) ++ memcpy(emac_pdata.mac_addr, davinci_bootloader_mac_addr, 6); + else { + /* Use random MAC if none passed */ + random_ether_addr(emac_pdata.mac_addr); +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0005-Add-DAS-Mini-DAS-and-AFE-USB-machine-types.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0005-Add-DAS-Mini-DAS-and-AFE-USB-machine-types.patch new file mode 100644 index 0000000000..4522059d30 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0005-Add-DAS-Mini-DAS-and-AFE-USB-machine-types.patch @@ -0,0 +1,135 @@ +From 138af04718e9d80ed75bf3aeb7fb89fee2f97c12 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 14:17:52 -0500 +Subject: [PATCH 05/12] Add DAS, Mini-DAS and AFE-USB machine types + +Signed-off-by: Hugo Villeneuve +--- + arch/arm/tools/mach-types | 100 ++++++++++++++++++++++++++++++++++++++++++++- + 1 files changed, 98 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types +index 017ceba..f8c2e34 100644 +--- a/arch/arm/tools/mach-types ++++ b/arch/arm/tools/mach-types +@@ -12,7 +12,7 @@ + # + # http://www.arm.linux.org.uk/developer/machines/?action=new + # +-# Last update: Thu Sep 25 10:10:50 2008 ++# Last update: Sun Nov 30 16:39:36 2008 + # + # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number + # +@@ -1771,7 +1771,7 @@ axs_ultrax MACH_AXS_ULTRAX AXS_ULTRAX 1779 + at572d940deb MACH_AT572D940DEB AT572D940DEB 1780 + davinci_da8xx_evm MACH_DAVINCI_DA8XX_EVM DAVINCI_DA8XX_EVM 1781 + ep9302 MACH_EP9302 EP9302 1782 +-at572d940hfeb MACH_AT572D940HFEB AT572D940HFEB 1783 ++at572d940hfek MACH_AT572D940HFEB AT572D940HFEB 1783 + cybook3 MACH_CYBOOK3 CYBOOK3 1784 + wdg002 MACH_WDG002 WDG002 1785 + sg560adsl MACH_SG560ADSL SG560ADSL 1786 +@@ -1899,3 +1899,99 @@ rut100 MACH_RUT100 RUT100 1908 + asusp535 MACH_ASUSP535 ASUSP535 1909 + htcraphael MACH_HTCRAPHAEL HTCRAPHAEL 1910 + sygdg1 MACH_SYGDG1 SYGDG1 1911 ++sygdg2 MACH_SYGDG2 SYGDG2 1912 ++seoul MACH_SEOUL SEOUL 1913 ++salerno MACH_SALERNO SALERNO 1914 ++ucn_s3c64xx MACH_UCN_S3C64XX UCN_S3C64XX 1915 ++msm7201a MACH_MSM7201A MSM7201A 1916 ++lpr1 MACH_LPR1 LPR1 1917 ++armadillo500fx MACH_ARMADILLO500FX ARMADILLO500FX 1918 ++g3evm MACH_G3EVM G3EVM 1919 ++z3_dm355 MACH_Z3_DM355 Z3_DM355 1920 ++w90p910evb MACH_W90P910EVB W90P910EVB 1921 ++w90p920evb MACH_W90P920EVB W90P920EVB 1922 ++w90p950evb MACH_W90P950EVB W90P950EVB 1923 ++w90n960evb MACH_W90N960EVB W90N960EVB 1924 ++camhd MACH_CAMHD CAMHD 1925 ++mvc100 MACH_MVC100 MVC100 1926 ++electrum_200 MACH_ELECTRUM_200 ELECTRUM_200 1927 ++htcjade MACH_HTCJADE HTCJADE 1928 ++memphis MACH_MEMPHIS MEMPHIS 1929 ++imx27sbc MACH_IMX27SBC IMX27SBC 1930 ++lextar MACH_LEXTAR LEXTAR 1931 ++mv88f6281gtw_ge MACH_MV88F6281GTW_GE MV88F6281GTW_GE 1932 ++ncp MACH_NCP NCP 1933 ++z32an_series MACH_Z32AN Z32AN 1934 ++tmq_capd MACH_TMQ_CAPD TMQ_CAPD 1935 ++omap3_wl MACH_OMAP3_WL OMAP3_WL 1936 ++chumby MACH_CHUMBY CHUMBY 1937 ++atsarm9 MACH_ATSARM9 ATSARM9 1938 ++davinci_dm365_evm MACH_DAVINCI_DM365_EVM DAVINCI_DM365_EVM 1939 ++bahamas MACH_BAHAMAS BAHAMAS 1940 ++das MACH_DAS DAS 1941 ++minidas MACH_MINIDAS MINIDAS 1942 ++vk1000 MACH_VK1000 VK1000 1943 ++centro MACH_CENTRO CENTRO 1944 ++ctera_2bay MACH_CTERA_2BAY CTERA_2BAY 1945 ++edgeconnect MACH_EDGECONNECT EDGECONNECT 1946 ++nd27000 MACH_ND27000 ND27000 1947 ++cobra MACH_GEMALTO_COBRA GEMALTO_COBRA 1948 ++ingelabs_comet MACH_INGELABS_COMET INGELABS_COMET 1949 ++pollux_wiz MACH_POLLUX_WIZ POLLUX_WIZ 1950 ++blackstone MACH_BLACKSTONE BLACKSTONE 1951 ++topaz MACH_TOPAZ TOPAZ 1952 ++aixle MACH_AIXLE AIXLE 1953 ++mw998 MACH_MW998 MW998 1954 ++nokia_rx51 MACH_NOKIA_RX51 NOKIA_RX51 1955 ++vsc5605ev MACH_VSC5605EV VSC5605EV 1956 ++nt98700dk MACH_NT98700DK NT98700DK 1957 ++icontact MACH_ICONTACT ICONTACT 1958 ++swarco_frcpu MACH_SWARCO_FRCPU SWARCO_FRCPU 1959 ++swarco_scpu MACH_SWARCO_SCPU SWARCO_SCPU 1960 ++bbox_p16 MACH_BBOX_P16 BBOX_P16 1961 ++bstd MACH_BSTD BSTD 1962 ++sbc2440ii MACH_SBC2440II SBC2440II 1963 ++pcm034 MACH_PCM034 PCM034 1964 ++neso MACH_NESO NESO 1965 ++wlnx_9g20 MACH_WLNX_9G20 WLNX_9G20 1966 ++omap_zoom2 MACH_OMAP_ZOOM2 OMAP_ZOOM2 1967 ++totemnova MACH_TOTEMNOVA TOTEMNOVA 1968 ++c5000 MACH_C5000 C5000 1969 ++unipo_at91sam9263 MACH_UNIPO_AT91SAM9263 UNIPO_AT91SAM9263 1970 ++ethernut5 MACH_ETHERNUT5 ETHERNUT5 1971 ++arm11 MACH_ARM11 ARM11 1972 ++cpuat9260 MACH_CPUAT9260 CPUAT9260 1973 ++cpupxa255 MACH_CPUPXA255 CPUPXA255 1974 ++cpuimx27 MACH_CPUIMX27 CPUIMX27 1975 ++cheflux MACH_CHEFLUX CHEFLUX 1976 ++eb_cpux9k2 MACH_EB_CPUX9K2 EB_CPUX9K2 1977 ++opcotec MACH_OPCOTEC OPCOTEC 1978 ++yt MACH_YT YT 1979 ++motoq MACH_MOTOQ MOTOQ 1980 ++bsb1 MACH_BSB1 BSB1 1981 ++acs5k MACH_ACS5K ACS5K 1982 ++milan MACH_MILAN MILAN 1983 ++quartzv2 MACH_QUARTZV2 QUARTZV2 1984 ++rsvp MACH_RSVP RSVP 1985 ++rmp200 MACH_RMP200 RMP200 1986 ++snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987 ++dsm320 MACH_DSM320 DSM320 1988 ++adsgcm MACH_ADSGCM ADSGCM 1989 ++ase2_400 MACH_ASE2_400 ASE2_400 1990 ++pizza MACH_PIZZA PIZZA 1991 ++spot_ngpl MACH_SPOT_NGPL SPOT_NGPL 1992 ++armata MACH_ARMATA ARMATA 1993 ++exeda MACH_EXEDA EXEDA 1994 ++mx31sf005 MACH_MX31SF005 MX31SF005 1995 ++f5d8231_4_v2 MACH_F5D8231_4_V2 F5D8231_4_V2 1996 ++q2440 MACH_Q2440 Q2440 1997 ++qq2440 MACH_QQ2440 QQ2440 1998 ++mini2440 MACH_MINI2440 MINI2440 1999 ++colibri300 MACH_COLIBRI300 COLIBRI300 2000 ++jades MACH_JADES JADES 2001 ++spark MACH_SPARK SPARK 2002 ++benzina MACH_BENZINA BENZINA 2003 ++blaze MACH_BLAZE BLAZE 2004 ++linkstation_ls_hgl MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL 2005 ++htcvenus MACH_HTCVENUS HTCVENUS 2006 ++afeusb MACH_AFEUSB AFEUSB 2117 +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0006-ALSA-ASoC-DaVinci-Fix-SFFSDR-compilation-error.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0006-ALSA-ASoC-DaVinci-Fix-SFFSDR-compilation-error.patch new file mode 100644 index 0000000000..bb03490c38 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0006-ALSA-ASoC-DaVinci-Fix-SFFSDR-compilation-error.patch @@ -0,0 +1,65 @@ +From 590c788288e545ef74b77129bc8f747b5365f5d3 Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 15 Jan 2009 15:40:35 -0500 +Subject: [PATCH 06/12] ALSA: ASoC: DaVinci: Fix SFFSDR compilation error. + +Remove dependency on sffsdr_fpga_set_codec_fs() when the +SFFSDR FPGA module is not selected. + +Signed-off-by: Hugo Villeneuve +--- + sound/soc/davinci/davinci-sffsdr.c | 20 +++++++++++++++++--- + 1 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c +index 1bbde3e..afb61bf 100644 +--- a/sound/soc/davinci/davinci-sffsdr.c ++++ b/sound/soc/davinci/davinci-sffsdr.c +@@ -25,7 +25,9 @@ + #include + #include + #include ++#ifdef CONFIG_SFFSDR_FPGA + #include ++#endif + + #include + #include +@@ -42,6 +44,17 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, + int fs; + int ret = 0; + ++ /* Fsref can be 32000, 44100 or 48000. */ ++ fs = params_rate(params); ++ ++#ifndef CONFIG_SFFSDR_FPGA ++ /* Without the FPGA module, the Fs is fixed at 44100 Hz */ ++ if (fs != 44100) { ++ pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n"); ++ return -EINVAL; ++ } ++#endif ++ + /* Set cpu DAI configuration: + * CLKX and CLKR are the inputs for the Sample Rate Generator. + * FSX and FSR are outputs, driven by the sample Rate Generator. */ +@@ -52,12 +65,13 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, + if (ret < 0) + return ret; + +- /* Fsref can be 32000, 44100 or 48000. */ +- fs = params_rate(params); +- + pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); + ++#ifndef CONFIG_SFFSDR_FPGA ++ return 0; ++#else + return sffsdr_fpga_set_codec_fs(fs); ++#endif + } + + static struct snd_soc_ops sffsdr_ops = { +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0007-ALSA-ASoC-Davinci-Fix-SFFSDR-FPGA-module-codec-FS.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0007-ALSA-ASoC-Davinci-Fix-SFFSDR-FPGA-module-codec-FS.patch new file mode 100644 index 0000000000..e4a5537b6e --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0007-ALSA-ASoC-Davinci-Fix-SFFSDR-FPGA-module-codec-FS.patch @@ -0,0 +1,57 @@ +From ca4b0f980f8b03374f48cbb4937d3ed3150c0c3e Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 17:04:41 -0500 +Subject: [PATCH 07/12] ALSA: ASoC: Davinci: Fix SFFSDR FPGA module codec FS bug. + +This prevented the FPGA from properly configuring the codec FS when +the SFFSDR FPGA was compiled as a module. + +Signed-off-by: Hugo Villeneuve +--- + sound/soc/davinci/davinci-sffsdr.c | 14 +++++++------- + 1 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c +index afb61bf..b20e36c 100644 +--- a/sound/soc/davinci/davinci-sffsdr.c ++++ b/sound/soc/davinci/davinci-sffsdr.c +@@ -25,10 +25,10 @@ + #include + #include + #include +-#ifdef CONFIG_SFFSDR_FPGA +-#include +-#endif + ++#if defined(CONFIG_SFFSDR_FPGA) || defined(CONFIG_SFFSDR_FPGA_MODULE) ++#include ++#endif + #include + #include + +@@ -47,7 +47,7 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, + /* Fsref can be 32000, 44100 or 48000. */ + fs = params_rate(params); + +-#ifndef CONFIG_SFFSDR_FPGA ++#if !defined(CONFIG_SFFSDR_FPGA) && !defined(CONFIG_SFFSDR_FPGA_MODULE) + /* Without the FPGA module, the Fs is fixed at 44100 Hz */ + if (fs != 44100) { + pr_debug("warning: only 44.1 kHz is supported without SFFSDR FPGA module\n"); +@@ -67,10 +67,10 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, + + pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); + +-#ifndef CONFIG_SFFSDR_FPGA +- return 0; +-#else ++#if defined(CONFIG_SFFSDR_FPGA) || defined(CONFIG_SFFSDR_FPGA_MODULE) + return sffsdr_fpga_set_codec_fs(fs); ++#else ++ return 0; + #endif + } + +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0008-ALSA-ASoC-Davinci-Fix-incorrect-machine-type-for.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0008-ALSA-ASoC-Davinci-Fix-incorrect-machine-type-for.patch new file mode 100644 index 0000000000..800f089d51 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0008-ALSA-ASoC-Davinci-Fix-incorrect-machine-type-for.patch @@ -0,0 +1,26 @@ +From 867883ee8c226ce2c3a43c9d815a2ad706b1c19e Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Thu, 5 Mar 2009 15:43:16 -0500 +Subject: [PATCH 08/12] ALSA: ASoC: Davinci: Fix incorrect machine type for SFFSDR board + +Signed-off-by: Hugo Villeneuve +--- + sound/soc/davinci/Kconfig | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig +index 7d3a85d..411a710 100644 +--- a/sound/soc/davinci/Kconfig ++++ b/sound/soc/davinci/Kconfig +@@ -21,7 +21,7 @@ config SND_DAVINCI_SOC_EVM + + config SND_DAVINCI_SOC_SFFSDR + tristate "SoC Audio support for SFFSDR" +- depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR ++ depends on SND_DAVINCI_SOC && MACH_SFFSDR + select SND_DAVINCI_SOC_I2S + select SND_SOC_PCM3008 + select SFFSDR_FPGA +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0009-sound-ASoC-Fix-DaVinci-module-unload-error.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0009-sound-ASoC-Fix-DaVinci-module-unload-error.patch new file mode 100644 index 0000000000..79a89bfa44 --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0009-sound-ASoC-Fix-DaVinci-module-unload-error.patch @@ -0,0 +1,54 @@ +From 8d9e736833e9e765098353117e022b96ccc72ab1 Mon Sep 17 00:00:00 2001 +From: Kevin Hilman +Date: Fri, 13 Feb 2009 19:36:37 -0800 +Subject: [PATCH 09/12] sound: ASoC: Fix DaVinci module unload error + +sound: ASoC: Fix DaVinci module unload error + +Fix for the error when the audio module is unloaded. On unregistering +the platform_device, platform_device_release will free the platform +data.If platform data is static the kernel panics when it is freed. +Instead use the platform device helper function to add data. + +This change has been tested on DM644x EVM, DM644x SFFSDR and DM355 EVM. + +Signed-off-by: Chaithrika U S +Signed-off-by: Kevin Hilman +Signed-off-by: Mark Brown +Signed-off-by: Jaroslav Kysela +--- + sound/soc/davinci/davinci-evm.c | 3 ++- + sound/soc/davinci/davinci-sffsdr.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c +index 9420c96..0297703 100644 +--- a/sound/soc/davinci/davinci-evm.c ++++ b/sound/soc/davinci/davinci-evm.c +@@ -225,7 +225,8 @@ static int __init evm_init(void) + + platform_set_drvdata(evm_snd_device, &evm_snd_devdata); + evm_snd_devdata.dev = &evm_snd_device->dev; +- evm_snd_device->dev.platform_data = data; ++ platform_device_add_data(evm_snd_device, &evm_snd_data, ++ sizeof(evm_snd_data)); + + ret = platform_device_add_resources(evm_snd_device, resources, 1); + if (ret) { +diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c +index b20e36c..f3c3185 100644 +--- a/sound/soc/davinci/davinci-sffsdr.c ++++ b/sound/soc/davinci/davinci-sffsdr.c +@@ -140,7 +140,8 @@ static int __init sffsdr_init(void) + + platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); + sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; +- sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; ++ platform_device_add_data(sffsdr_snd_device, &sffsdr_snd_data, ++ sizeof(sffsdr_snd_data)); + + ret = platform_device_add_resources(sffsdr_snd_device, + sffsdr_snd_resources, +-- +1.5.4.5 + diff --git a/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch new file mode 100644 index 0000000000..0e034f609a --- /dev/null +++ b/packages/linux/linux-davinci-2.6.28/davinci-sffsdr/0010-Add-generic-FPGA-bitstream-loader-driver.patch @@ -0,0 +1,1512 @@ +From 500b0887632165f77f2604b07df746b4a3a16d2c Mon Sep 17 00:00:00 2001 +From: Hugo Villeneuve +Date: Fri, 6 Mar 2009 10:23:44 -0500 +Subject: [PATCH 10/12] Add generic FPGA bitstream loader driver + +This driver is a generic interface for programming a +bitstream into a FPGA. It can work with serial or +parallel programming interfaces and support multiple +devices and partial reconfiguration. Currently Xilinx +XC3S and XC4V FPGAs are implemented, but other +manufacturers like Altera could be easily added. + +Signed-off-by: Hugo Villeneuve +--- + drivers/misc/Kconfig | 31 ++ + drivers/misc/Makefile | 3 + + drivers/misc/fpgadl.c | 806 +++++++++++++++++++++++++++++++++++++++++++++ + drivers/misc/fpgadl_par.c | 258 +++++++++++++++ + drivers/misc/fpgadl_ser.c | 244 ++++++++++++++ + include/linux/fpgadl.h | 96 ++++++ + 6 files changed, 1438 insertions(+), 0 deletions(-) + create mode 100644 drivers/misc/fpgadl.c + create mode 100644 drivers/misc/fpgadl_par.c + create mode 100644 drivers/misc/fpgadl_ser.c + create mode 100644 include/linux/fpgadl.h + +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index a11e2a0..bdc0517 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -510,6 +510,37 @@ config SGI_GRU_DEBUG + This option enables addition debugging code for the SGI GRU driver. If + you are unsure, say N. + ++config FPGADL ++ tristate "FPGA bitstream loader support" ++ help ++ This option enables support for the FPGA bitstream loader. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called fpgadl. ++ ++ If unsure, say N. ++ ++config FPGADL_SER ++ tristate "FPGA serial programming driver" ++ depends on SPI_MASTER && FPGADL ++ help ++ Say Y here if your FPGA bitstream is loaded using a serial ++ interface (SPI). ++ ++ To compile this driver as a module, choose M here: the ++ module will be called fpgadl_ser. ++ ++config FPGADL_PAR ++ tristate "FPGA parallel programming driver" ++ depends on FPGADL ++ select BITREVERSE ++ help ++ Say Y here if your FPGA bitstream is loaded using a parallel ++ interface. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called fpgadl_par. ++ + source "drivers/misc/c2port/Kconfig" + + endif # MISC_DEVICES +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 78be134..4fb6dfc 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -32,5 +32,8 @@ obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o + obj-$(CONFIG_KGDB_TESTS) += kgdbts.o + obj-$(CONFIG_SGI_XP) += sgi-xp/ + obj-$(CONFIG_SGI_GRU) += sgi-gru/ ++obj-$(CONFIG_FPGADL) += fpgadl.o ++obj-$(CONFIG_FPGADL_SER) += fpgadl_ser.o ++obj-$(CONFIG_FPGADL_PAR) += fpgadl_par.o + obj-$(CONFIG_HP_ILO) += hpilo.o + obj-$(CONFIG_C2PORT) += c2port/ +diff --git a/drivers/misc/fpgadl.c b/drivers/misc/fpgadl.c +new file mode 100644 +index 0000000..2f03d9b +--- /dev/null ++++ b/drivers/misc/fpgadl.c +@@ -0,0 +1,806 @@ ++/* ++ * fpgadl core driver ++ * ++ * Copyright (C) 2008 Lyrtech ++ * ++ * Based on code found in book "Linux Device Drivers" by ++ * Alessandro Rubini and Jonathan Corbet, published by O'Reilly & Associates. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define MODULE_NAME "fpgadl" ++ ++/* Define this to enable verbose debug messages */ ++#define FPGADL_DEBUG 1 ++ ++static const char fpgadl_driver_version[] = "v1.0"; ++ ++/* Module parameters */ ++static unsigned int fpgadl_debug; ++EXPORT_SYMBOL_GPL(fpgadl_debug); ++module_param_named(debug, fpgadl_debug, int, 0644); ++ ++#ifdef FPGADL_DEBUG ++#define INFOMSG(fmt, args...) \ ++ do { \ ++ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); \ ++ } while (0) ++#define DBGMSG(fmt, args...) \ ++ do { \ ++ if (fpgadl_debug > 0) \ ++ printk(KERN_DEBUG "%s: "fmt"\n", \ ++ MODULE_NAME, ## args); \ ++ } while (0) ++#define DBGMSG_ENTER() \ ++ DBGMSG("%s() enter", __func__); ++#define DBGMSG_LEAVE() \ ++ DBGMSG("%s() leave", __func__); ++#else ++#define INFOMSG(fmt, args...) do {} while (0) ++#define DBGMSG(fmt, args...) do {} while (0) ++#define DBGMSG_ENTER() do {} while (0) ++#define DBGMSG_LEAVE() do {} while (0) ++#endif ++ ++#define FAILMSG(fmt, args...) \ ++ do { \ ++ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); \ ++ } while (0) ++ ++#define FPGA_WAIT_TIMEOUT 100000 ++#define XFER_SIZE 100 /* Transfer size when writing bytes to ++ * device. */ ++ ++#define BITSTREAM_MAX_SIZE_OVERHEAD 10240 ++ ++#define XC3S_WORD_SIZE 2 ++#define XC4V_WORD_SIZE 4 ++ ++#define BITSTREAM_SYNC_BYTE1 0xAA ++#define BITSTREAM_SYNC_BYTE2 0x99 ++#define BITSTREAM_SYNC_BYTE3 0x55 ++#define BITSTREAM_SYNC_BYTE4 0x66 ++ ++#define BITSTREAM_PACKET_HEADER_TYPE1 1 ++#define BITSTREAM_PACKET_HEADER_TYPE2 2 ++#define BITSTREAM_TYPE1_OPCODE_WRITE 2 ++#define BITSTREAM_TYPE1_REG_ADDR_FDRI 2 ++ ++/* Structure of a TYPE1 packet. */ ++struct t1_pkt_xc4v_t { ++ u32 word_count:11; ++ u32 reserved2:2; ++ u32 address:5; ++ u32 reserved1:9; ++ u32 opcode:2; ++ u32 header:3; ++}; ++ ++struct t1_pkt_xc3s_t { ++ u16 word_count:5; ++ u16 address:6; ++ u16 opcode:2; ++ u16 header:3; /* type */ ++}; ++ ++/* Structure of a TYPE2 packet. */ ++struct t2_pkt_xc4v_t { ++ u32 word_count:27; ++ u32 opcode:2; /* Reserved. */ ++ u32 header:3; ++}; ++ ++struct t2_pkt_xc3s_t { ++ u16 word_count:11; ++ u16 opcode:2; /* Reserved. */ ++ u16 header:3; ++}; ++ ++#define MAX_FPGADL_DEV 4 ++ ++static int fpgadl_dev_count; ++static struct fpgadl_device *fpgadl_dev_array[MAX_FPGADL_DEV]; ++ ++int fpgadl_is_bitstream_loaded(const char *name) ++{ ++ int k; ++ struct fpgadl_device *fpgadl_dev; ++ ++ DBGMSG_ENTER(); ++ ++ for (k = 0; k < MAX_FPGADL_DEV; k++) { ++ fpgadl_dev = fpgadl_dev_array[k]; ++ if (fpgadl_dev) ++ if (strncmp(fpgadl_dev->name, name, strlen(name)) == 0) ++ return fpgadl_dev->bitstream_loaded; ++ } ++ ++ FAILMSG(" Device <%s> not found", name); ++ return -ENOMEM; ++} ++EXPORT_SYMBOL(fpgadl_is_bitstream_loaded); ++ ++/* Respond to hotplug events. */ ++static int fpgadl_uevent(struct device *dev, struct kobj_uevent_env *env) ++{ ++ DBGMSG_ENTER(); ++ ++ if (add_uevent_var(env, "FPGADL_BUS_VERSION=%s", fpgadl_driver_version)) ++ return -ENOMEM; ++ return 0; ++}; ++ ++/* ++ * Toggles the CCLK line on the board-specific interface the number of times ++ * specified by . ++ */ ++static int bitstr_load_make_clock(struct fpgadl_device *fpgadl_dev, ++ int cycles) ++{ ++ int retval; ++ int k; ++ u8 dummy = 0; ++ ++ for (k = 0; k < cycles; k++) { ++ retval = fpgadl_dev->write_byte(fpgadl_dev, &dummy, 1); ++ if (retval < 0) ++ return retval; ++ } ++ ++ return 0; ++} ++ ++/* Search for bitstream sync word. */ ++static int bitstr_search_sync_word(const u8 *buffer, size_t length, ++ const u8 *sync_word, ssize_t sync_word_size) ++{ ++ int k; ++ ++ for (k = 0; k < length; k++, buffer++) { ++ if (memcmp(buffer, sync_word, sync_word_size) == 0) { ++ DBGMSG(" Synchronization word found at offset 0x%02X", ++ k); ++ return k; ++ } ++ } ++ ++ return 0; ++} ++ ++static int bitstr_get_payload_size(int fpga_family, int sws, ++ const u8 *buffer, ssize_t length) ++{ ++ int index = 0; ++ ++ /* Find the payload size. */ ++ while (index < length) { ++ switch (fpga_family) { ++ case FPGA_FAMILY_XILINX_XC4V: ++ { ++ u32 tmp = ntohl(*((u32 *) &buffer[index])); ++ struct t1_pkt_xc4v_t *t1 = ++ (struct t1_pkt_xc4v_t *) &tmp; ++ ++ /* Search for type 1 packet header. */ ++ if ((t1->header == BITSTREAM_PACKET_HEADER_TYPE1) && ++ (t1->opcode == BITSTREAM_TYPE1_OPCODE_WRITE) && ++ (t1->address == BITSTREAM_TYPE1_REG_ADDR_FDRI)) { ++ if (t1->word_count != 0) ++ return t1->word_count; ++ else { ++ struct t2_pkt_xc4v_t *t2; ++ ++ tmp = ntohl(*((u32 *) ++ &buffer[index + sws])); ++ t2 = (struct t2_pkt_xc4v_t *) &tmp; ++ ++ /* Search for type 2 packet header just ++ * after type1 packet. */ ++ if ((t2->header == ++ BITSTREAM_PACKET_HEADER_TYPE2)) ++ return t2->word_count; ++ } ++ } ++ } ++ break; ++ case FPGA_FAMILY_XILINX_XC3S: ++ { ++ u16 tmp = ntohs(*((u16 *) &buffer[index])); ++ struct t2_pkt_xc3s_t *t2 = ++ (struct t2_pkt_xc3s_t *) &tmp; ++ ++ /* Search for type 2 packet header just after ++ * type1 packet. */ ++ if ((t2->header == BITSTREAM_PACKET_HEADER_TYPE2)) { ++ DBGMSG(" Type 2 packet found at offset $%02X", ++ index); ++ return ntohl(*((u32 *) &buffer[index + sws])); ++ } ++ /* Word-size aligned when sync word has been found. */ ++ index += sws; ++ } ++ break; ++ } ++ ++ /* Word-size aligned when sync word has been found. */ ++ index += sws; ++ } ++ ++ return 0; /* Not found */ ++} ++ ++/* ++ * Return value: ++ * 0: Error ++ * 1: Full bitstream ++ * 2: Partial bitstream ++ */ ++static int bitstream_parse_header(const u8 *buffer, size_t length, ++ int fpga_family, size_t payload_full_size) ++{ ++ int index = 0; ++ size_t payload_size = 0; ++ u8 sync_word[] = { ++ BITSTREAM_SYNC_BYTE1, ++ BITSTREAM_SYNC_BYTE2, ++ BITSTREAM_SYNC_BYTE3, ++ BITSTREAM_SYNC_BYTE4, ++ }; ++ int sync_word_size; /* Size in bytes */ ++ ++ switch (fpga_family) { ++ case FPGA_FAMILY_XILINX_XC3S: ++ sync_word_size = XC3S_WORD_SIZE; ++ break; ++ case FPGA_FAMILY_XILINX_XC4V: ++ sync_word_size = XC4V_WORD_SIZE; ++ break; ++ default: ++ FAILMSG("Error, invalid FPGA family number"); ++ return BITSTREAM_MODE_UNKNOWN; ++ } ++ ++ /* Search for bitstream sync word. */ ++ index = bitstr_search_sync_word(buffer, length, ++ sync_word, sync_word_size); ++ if (index == 0) { ++ FAILMSG("Error: Synchronization word not found"); ++ return BITSTREAM_MODE_UNKNOWN; ++ } ++ ++ /* Get payload size. */ ++ payload_size = bitstr_get_payload_size(fpga_family, sync_word_size, ++ &buffer[index], length - index); ++ payload_size *= sync_word_size; /* Length in bytes. */ ++ ++ if (payload_size == 0) { ++ /* Warning only, assuming FULL bitstream. */ ++ DBGMSG(" Warning: payload size not found"); ++ return BITSTREAM_MODE_FULL; ++ } else { ++ DBGMSG(" Payload size: %d kb", payload_size / 1024); ++ ++ /* Is it a full or a partial bitstream? */ ++ if (payload_size == payload_full_size) ++ return BITSTREAM_MODE_FULL; ++ else ++ return BITSTREAM_MODE_PARTIAL; ++ } ++} ++ ++/* ++ * Bitstreams supported: Full or Partial. ++ * Note: Full bitstream that supports partial bitstream must be generated with ++ * option "Persist = true" in ISE. ++ */ ++static int fpgadl_bitstream_load(struct fpgadl_device *fpgadl_dev, ++ const u8 *data, size_t size) ++{ ++ int k; ++ int retval; ++ int timeout_counter; ++ ++ fpgadl_dev->bitstream_loaded = 0; ++ ++ fpgadl_dev->bitstream_mode = ++ bitstream_parse_header(data, size, ++ fpgadl_dev->pdata->fpga_family, ++ fpgadl_dev->pdata->payload_full_size); ++ switch (fpgadl_dev->bitstream_mode) { ++ case BITSTREAM_MODE_FULL: ++ DBGMSG(" Bitstream type: FULL"); ++ /* Toggle PROG_B Pin and wait 300nS before proceeding. */ ++ gpio_set_value(fpgadl_dev->pdata->program_b, 0); ++ udelay(1); ++ ++ /* Confirm that INIT_B is low */ ++ if (gpio_get_value(fpgadl_dev->pdata->init_b) != 0) { ++ FAILMSG("Error: INIT_B not LOW when PROG is LOW"); ++ return -EIO; ++ } ++ ++ break; ++ case BITSTREAM_MODE_PARTIAL: ++ DBGMSG(" Bitstream type: PARTIAL"); ++ break; ++ case BITSTREAM_MODE_UNKNOWN: ++ default: ++ FAILMSG(" Bitstream type: UNKNOWN"); ++ return -EINVAL; ++ break; ++ } ++ ++ /* For partial bitstream, PROGRAM_B is already high. */ ++ retval = bitstr_load_make_clock(fpgadl_dev, 3); ++ if (retval < 0) ++ return retval; ++ ++ gpio_set_value(fpgadl_dev->pdata->program_b, 1); ++ ++ /* Wait for INIT_B pin to go high. */ ++ timeout_counter = 0; ++ while ((gpio_get_value(fpgadl_dev->pdata->init_b) == 0) && ++ (timeout_counter < FPGA_WAIT_TIMEOUT)) { ++ retval = bitstr_load_make_clock(fpgadl_dev, 3); ++ if (retval < 0) ++ return retval; ++ ++ timeout_counter++; ++ } ++ ++ if (timeout_counter == FPGA_WAIT_TIMEOUT) { ++ /* Timeout error. */ ++ FAILMSG("Error: timeout while waiting for INIT_B to go HIGH"); ++ return -EIO; ++ } ++ ++ /* Send actual bitstream data to FPGA one byte at a time. */ ++ for (k = 0; k < size; k += XFER_SIZE) { ++ retval = fpgadl_dev->write_byte(fpgadl_dev, ++ (u8 *) &data[k], XFER_SIZE); ++ if (retval < 0) ++ return retval; ++ ++ if (fpgadl_dev->pdata->check_init_low) { ++ if (gpio_get_value(fpgadl_dev->pdata->init_b) == 0) { ++ /* Error if INIT_B goes low here. */ ++ FAILMSG("Error: INIT_B LOW during programming"); ++ return -EIO; ++ } ++ } ++ } ++ ++ /* Pulse the clock line ten times at the end. */ ++ retval = bitstr_load_make_clock(fpgadl_dev, 10); ++ if (retval < 0) ++ return retval; ++ ++ /* FPGA DONE pin must go high. */ ++ timeout_counter = 0; ++ while ((gpio_get_value(fpgadl_dev->pdata->done) == 0) && ++ (timeout_counter < FPGA_WAIT_TIMEOUT)) ++ timeout_counter++; ++ ++ if (gpio_get_value(fpgadl_dev->pdata->done) == 0) { ++ /* Timeout error. */ ++ FAILMSG("Error: timeout while waiting for DONE to go HIGH"); ++ return -EIO; ++ } ++ ++ INFOMSG("Bitstream loaded"); ++ fpgadl_dev->bitstream_loaded = 1; ++ ++ return 0; ++} ++ ++/* Open method. */ ++static int fpgadl_open(struct inode *inode, struct file *filp) ++{ ++ int k; ++ int found = 0; ++ struct fpgadl_device *fpgadl_dev; ++ ++ DBGMSG_ENTER(); ++ DBGMSG(" Opening device minor %d", MINOR(inode->i_rdev)); ++ ++ for (k = 0; k < fpgadl_dev_count; k++) { ++ fpgadl_dev = fpgadl_dev_array[k]; ++ if (fpgadl_dev) { ++ if (fpgadl_dev->miscdev.minor == MINOR(inode->i_rdev)) { ++ found = 1; ++ break; ++ } ++ } ++ } ++ ++ if (!found) { ++ FAILMSG(" Invalid minor device"); ++ return -ENOMEM; ++ } ++ ++ filp->private_data = fpgadl_dev; ++ ++ fpgadl_dev->bitstream_length = 0; ++ fpgadl_dev->bitstream_data = kmalloc(fpgadl_dev->bitstream_max_size, ++ GFP_KERNEL); ++ if (!fpgadl_dev->bitstream_data) { ++ FAILMSG("Failed to allocate memory for bitstream"); ++ return -ENOMEM; ++ } ++ ++ fpgadl_dev->bitstream_buffer_allocated = 1; ++ ++ return 0; ++} ++ ++/* Write method. Fill buffer with bitstream data. */ ++static ssize_t fpgadl_write(struct file *filp, const char __user *buff, ++ size_t count, loff_t *offp) ++{ ++ struct fpgadl_device *fpgadl_dev = filp->private_data; ++ ++ if ((fpgadl_dev->bitstream_length + count) >= ++ fpgadl_dev->bitstream_max_size) { ++ FAILMSG("Bitstream buffer size exceeded"); ++ return -EFBIG; ++ } ++ ++ if (copy_from_user(fpgadl_dev->bitstream_data + ++ fpgadl_dev->bitstream_length, ++ (void __user *) buff, count)) ++ return -EFAULT; ++ ++ fpgadl_dev->bitstream_length += count; ++ ++ return count; ++} ++ ++/* Release method. This will initiate the FPGA programming. */ ++static int fpgadl_release(struct inode *inode, struct file *filp) ++{ ++ int retval; ++ struct fpgadl_device *fpgadl_dev = filp->private_data; ++ ++ if (!fpgadl_dev->bitstream_data) ++ return -EFAULT; ++ ++ retval = fpgadl_bitstream_load(fpgadl_dev, ++ fpgadl_dev->bitstream_data, ++ fpgadl_dev->bitstream_length); ++ kfree(fpgadl_dev->bitstream_data); ++ fpgadl_dev->bitstream_buffer_allocated = 0; ++ ++ return retval; ++} ++ ++static struct file_operations fops_fpgadl = { ++ .owner = THIS_MODULE, ++ .open = fpgadl_open, ++ .write = fpgadl_write, ++ .release = fpgadl_release ++}; ++ ++/* Match fpgadl devices to drivers. Just do a simple name test. */ ++static int fpgadl_device_match(struct device *dev, ++ struct device_driver *drv) ++{ ++ DBGMSG_ENTER(); ++ return !strncmp(dev->bus_id, drv->name, strlen(drv->name)); ++} ++ ++static ssize_t show_version(struct device_driver *driver, char *buf) ++{ ++ struct fpgadl_driver *fpgadldriver = to_fpgadl_driver(driver); ++ ++ sprintf(buf, "%s\n", fpgadldriver->version); ++ return strlen(buf); ++} ++ ++int fpgadl_register_driver(struct fpgadl_driver *drv) ++{ ++ int res; ++ ++ DBGMSG_ENTER(); ++ ++ /* Initialize common driver fields */ ++ drv->driver.bus = &fpgadl_bus_type; ++ ++ /* Register with core */ ++ res = driver_register(&drv->driver); ++ if (res) ++ FAILMSG(" driver_register() failed"); ++ ++ drv->version_attr.attr.name = "version"; ++ drv->version_attr.attr.owner = drv->module; ++ drv->version_attr.attr.mode = S_IRUGO; ++ drv->version_attr.show = show_version; ++ drv->version_attr.store = NULL; ++ res = driver_create_file(&drv->driver, &drv->version_attr); ++ ++ return res; ++} ++EXPORT_SYMBOL(fpgadl_register_driver); ++ ++void fpgadl_unregister_driver(struct fpgadl_driver *drv) ++{ ++ DBGMSG_ENTER(); ++ driver_unregister(&drv->driver); ++} ++EXPORT_SYMBOL(fpgadl_unregister_driver); ++ ++/* The fpgadl bus device. */ ++static void fpgadl_bus_release(struct device *dev) ++{ ++ DBGMSG_ENTER(); ++} ++ ++struct device fpgadl_bus = { ++ .bus_id = "fpgadl0", ++ .release = fpgadl_bus_release ++}; ++ ++struct bus_type fpgadl_bus_type = { ++ .name = "fpgadl", ++ .match = fpgadl_device_match, ++ .uevent = fpgadl_uevent, ++}; ++EXPORT_SYMBOL(fpgadl_bus_type); ++ ++/* Export a simple sysfs attribute. */ ++static ssize_t show_bus_version(struct bus_type *bus, char *buf) ++{ ++ return snprintf(buf, PAGE_SIZE, "%s\n", fpgadl_driver_version); ++} ++ ++static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); ++ ++/* ++ * fpgadl devices. ++ * For now, no references to fpgadlbus devices go out which are not ++ * tracked via the module reference count, so we use a no-op ++ * release function. ++ */ ++static void fpgadl_dev_release(struct device *dev) ++{ ++ DBGMSG_ENTER(); ++} ++ ++/* Release DaVinci GPIO to FPGA control pins. */ ++static void fpgadl_release_gpio(struct fpgadl_pdata_t *pdata) ++{ ++ gpio_free(pdata->done); ++ gpio_free(pdata->init_b); ++ gpio_free(pdata->program_b); ++} ++ ++static int fpgadl_setup_gpio(struct fpgadl_pdata_t *pdata) ++{ ++ int retval; ++ ++ /* Configure FPGA PROGRAM_B GPIO. */ ++ retval = gpio_request(pdata->program_b, "fpga_program_b"); ++ if (retval == 0) /* FPGA_PROGRAM_B must be initially HIGH. */ ++ retval = gpio_direction_output(pdata->program_b, 1); ++ if (retval != 0) ++ goto gpio_error; ++ ++ /* Configure FPGA INIT_B GPIO. */ ++ retval = gpio_request(pdata->init_b, "fpga_init_b"); ++ if (retval == 0) ++ retval = gpio_direction_input(pdata->init_b); ++ if (retval != 0) ++ goto gpio_error; ++ ++ /* Configure FPGA DONE GPIO. */ ++ retval = gpio_request(pdata->done, "fpga_done"); ++ if (retval == 0) ++ retval = gpio_direction_input(pdata->done); ++ if (retval != 0) ++ goto gpio_error; ++ ++ return 0; ++ ++gpio_error: ++ fpgadl_release_gpio(pdata); ++ return retval; ++} ++ ++static void fpgadl_cleanup(struct fpgadl_device *fpgadl_dev) ++{ ++ DBGMSG_ENTER(); ++ ++ if (!fpgadl_dev) ++ return; ++ ++ fpgadl_dev_array[fpgadl_dev->id] = NULL; ++ ++ /* Get rid of any allocated buffer, not freed */ ++ if (fpgadl_dev->bitstream_buffer_allocated) ++ kfree(fpgadl_dev->bitstream_data); ++ ++ switch (fpgadl_dev->state) { ++ case FPGADL_DEV_STATE_CHAR_DEV_REGISTERED: ++ misc_deregister(&fpgadl_dev->miscdev); ++ case FPGADL_DEV_STATE_GPIO_REGISTERED: ++ fpgadl_release_gpio(fpgadl_dev->pdata); ++ case FPGADL_DEV_STATE_DEVICE_REGISTERED: ++ device_unregister(&fpgadl_dev->dev); ++ case FPGADL_DEV_STATE_START: ++ break; ++ } ++} ++ ++int fpgadl_register_device(struct fpgadl_device *fpgadl_dev) ++{ ++ int res; ++ const struct firmware *fw_entry; ++ ++ DBGMSG_ENTER(); ++ ++ fpgadl_dev->state = FPGADL_DEV_STATE_START; ++ ++ /* Sanity checks. */ ++ if (!fpgadl_dev->name) { ++ FAILMSG(" Error, missing device name"); ++ res = -EFAULT; ++ goto error; ++ } ++ ++ if (!fpgadl_dev->write_byte) { ++ FAILMSG(" Error, missing write_byte() callback"); ++ res = -ENOMEM; ++ goto error; ++ } ++ ++ if (fpgadl_dev_count == MAX_FPGADL_DEV) { ++ FAILMSG("Maximum number of devices reached (%d)", ++ fpgadl_dev_count); ++ res = -ENODEV; ++ goto error; ++ } ++ ++ DBGMSG(" device %d", fpgadl_dev_count); ++ ++ /* Set some default values. */ ++ fpgadl_dev->bitstream_loaded = 0; ++ fpgadl_dev->bitstream_buffer_allocated = 0; ++ fpgadl_dev->bitstream_max_size = ++ fpgadl_dev->pdata->payload_full_size + ++ BITSTREAM_MAX_SIZE_OVERHEAD; ++ ++ fpgadl_dev->dev.bus = &fpgadl_bus_type; ++ fpgadl_dev->dev.parent = &fpgadl_bus; ++ fpgadl_dev->dev.release = fpgadl_dev_release; ++ strncpy(fpgadl_dev->dev.bus_id, fpgadl_dev->name, BUS_ID_SIZE); ++ res = device_register(&fpgadl_dev->dev); ++ if (res) { ++ FAILMSG(" device_register() failed"); ++ goto error; ++ } ++ fpgadl_dev->state = FPGADL_DEV_STATE_DEVICE_REGISTERED; ++ ++ res = fpgadl_setup_gpio(fpgadl_dev->pdata); ++ if (res < 0) { ++ FAILMSG("Error registering GPIOs"); ++ goto error; ++ } ++ fpgadl_dev->state = FPGADL_DEV_STATE_GPIO_REGISTERED; ++ ++ fpgadl_dev->miscdev.name = fpgadl_dev->name; ++ fpgadl_dev->miscdev.minor = MISC_DYNAMIC_MINOR; ++ fpgadl_dev->miscdev.fops = &fops_fpgadl; ++ res = misc_register(&fpgadl_dev->miscdev); ++ if (res < 0) { ++ FAILMSG("Error registering misc driver"); ++ goto error; ++ } ++ DBGMSG(" MINOR = %d", fpgadl_dev->miscdev.minor); ++ fpgadl_dev->state = FPGADL_DEV_STATE_CHAR_DEV_REGISTERED; ++ ++ /* Try to load firmware through hotplug if available. */ ++ res = request_firmware(&fw_entry, fpgadl_dev->pdata->bitstream_name, ++ &fpgadl_dev->dev); ++ if (res < 0) { ++ /* Not an error preventing the driver from being loaded. */ ++ res = 0; ++ DBGMSG("Info: firmware not available"); ++ } else { ++ res = fpgadl_bitstream_load(fpgadl_dev, fw_entry->data, ++ fw_entry->size); ++ release_firmware(fw_entry); ++ } ++ ++ fpgadl_dev->id = fpgadl_dev_count; ++ fpgadl_dev_array[fpgadl_dev_count] = fpgadl_dev; ++ fpgadl_dev_count++; ++ ++ return 0; ++ ++error: ++ fpgadl_cleanup(fpgadl_dev); ++ return res; ++} ++EXPORT_SYMBOL(fpgadl_register_device); ++ ++void fpgadl_unregister_device(struct fpgadl_device *fpgadl_dev) ++{ ++ DBGMSG_ENTER(); ++ fpgadl_cleanup(fpgadl_dev); ++} ++EXPORT_SYMBOL(fpgadl_unregister_device); ++ ++static int __init fpgadl_init(void) ++{ ++ int res; ++ ++ DBGMSG_ENTER(); ++ INFOMSG("FPGA bitstream loader %s", fpgadl_driver_version); ++ ++ res = bus_register(&fpgadl_bus_type); ++ if (res) { ++ FAILMSG(" bus_register() failed"); ++ goto fail_bus; ++ } ++ ++ if (bus_create_file(&fpgadl_bus_type, &bus_attr_version)) { ++ FAILMSG("Unable to create version attribute"); ++ goto fail_create_file; ++ } ++ ++ res = device_register(&fpgadl_bus); ++ if (res) { ++ FAILMSG(" failed registering %s", fpgadl_bus.bus_id); ++ goto fail_dev_reg; ++ } ++ ++ return 0; ++ ++fail_dev_reg: ++fail_create_file: ++ bus_unregister(&fpgadl_bus_type); ++fail_bus: ++ return res; ++} ++module_init(fpgadl_init); ++ ++static void __exit fpgadl_exit(void) ++{ ++ DBGMSG_ENTER(); ++ device_unregister(&fpgadl_bus); ++ bus_unregister(&fpgadl_bus_type); ++} ++module_exit(fpgadl_exit); ++ ++MODULE_AUTHOR("Hugo Villeneuve "); ++MODULE_DESCRIPTION("FPGA bitstream loader"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/fpgadl_par.c b/drivers/misc/fpgadl_par.c +new file mode 100644 +index 0000000..66f8eba +--- /dev/null ++++ b/drivers/misc/fpgadl_par.c +@@ -0,0 +1,258 @@ ++/* ++ * fpgadl_par.c - FPGA parallel programming driver ++ * ++ * Copyright (C) 2008 Lyrtech ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include /* For ioremap() */ ++ ++#define MODULE_NAME "fpgadl_par" ++#define MODULE_VERSION_STR "v1.0" ++ ++/* Define this to enable verbose debug messages */ ++#define FPGADL_PAR_DEBUG 1 ++ ++/* Module parameters */ ++static unsigned int fpgadl_par_debug; ++EXPORT_SYMBOL_GPL(fpgadl_par_debug); ++module_param_named(debug, fpgadl_par_debug, int, 0644); ++ ++#ifdef FPGADL_PAR_DEBUG ++#define INFOMSG(fmt, args...) \ ++do { \ ++ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++#define DBGMSG(fmt, args...) \ ++do { if (fpgadl_par_debug > 0) \ ++ printk(KERN_DEBUG "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++#define DBGMSG_ENTER() \ ++ DBGMSG("%s() enter", __func__); ++#define DBGMSG_LEAVE() \ ++ DBGMSG("%s() leave", __func__); ++#else ++#define INFOMSG(fmt, args...) do {} while (0) ++#define DBGMSG(fmt, args...) do {} while (0) ++#define DBGMSG_ENTER() do {} while (0) ++#define DBGMSG_LEAVE() do {} while (0) ++#endif ++ ++#define FAILMSG(fmt, args...) \ ++do { \ ++ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++ ++struct fpgadl_par_dev_t { ++ char devname[32]; ++ enum { ++ FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED, ++ FPGADL_PAR_DEV_STATE_HAVE_IOREMAP, ++ FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED, ++ } state; ++ u8 *selectmap; ++ struct fpgadl_device fpgadl_dev; ++}; ++ ++#define MAX_FPGADL_PAR_DEV 5 ++ ++static int fpgadl_par_dev_count; ++ ++/* ++ * Writes a byte of data to the FPGA using the SelectMAP ++ * interface. The FPGA_SELECT_MAP_REG address is within ++ * the FPGA address space (CS3), and when we write a byte ++ * to that address, the CCLK line will be toggled. ++ */ ++static int selectmap_write_byte(struct fpgadl_device *fpgadl_dev, ++ u8 *data, int size) ++{ ++ int k; ++ struct fpgadl_par_dev_t *fpgadl_par_dev; ++ ++ fpgadl_par_dev = (struct fpgadl_par_dev_t *) fpgadl_dev->devdata; ++ ++ for (k = 0; k < size; k++) ++ fpgadl_par_dev->selectmap[0] = bitrev8(data[k]); ++ ++ return 0; ++} ++ ++static void fpgadl_par_cleanup(struct fpgadl_par_dev_t *dev) ++{ ++ DBGMSG("fpgadl_par_cleanup"); ++ ++ if (!dev) ++ return; ++ ++ switch (dev->state) { ++ case FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED: ++ fpgadl_unregister_device(&dev->fpgadl_dev); ++ case FPGADL_PAR_DEV_STATE_HAVE_IOREMAP: ++ iounmap(dev->selectmap); ++ case FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED: ++ kfree(dev); ++ break; ++ } ++} ++ ++static int __devinit fpgadl_par_probe(struct platform_device *pdev) ++{ ++ int len; ++ int res; ++ struct fpgadl_par_dev_t *dev = NULL; ++ const struct resource *selectmap_res; ++ ++ DBGMSG("fpgadl_par_probe()"); ++ ++ if (fpgadl_par_dev_count == MAX_FPGADL_PAR_DEV) { ++ FAILMSG("Maximum number of devices reached (%d)", ++ fpgadl_par_dev_count); ++ res = -ENODEV; ++ goto error; ++ } ++ ++ DBGMSG(" device %d", fpgadl_par_dev_count); ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) { ++ FAILMSG("Failed to allocate device structure"); ++ res = -ENOMEM; ++ goto error; ++ } ++ /* Set some default values. */ ++ dev->state = FPGADL_PAR_DEV_STATE_STRUCT_ALLOCATED; ++ ++ if (!pdev->dev.platform_data) { ++ FAILMSG("Error getting platform data"); ++ res = -ENODEV; ++ goto error; ++ } ++ dev->fpgadl_dev.pdata = pdev->dev.platform_data; ++ pdev->dev.driver_data = dev; /* Private driver data */ ++ ++ /* Assign virtual addresses to SELECTMAP I/O memory regions. */ ++ selectmap_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, ++ "selectmap"); ++ if (!selectmap_res) { ++ FAILMSG("Error getting selectmap ressource"); ++ res = -ENODEV; ++ goto error; ++ } ++ len = selectmap_res->end - selectmap_res->start; ++ dev->selectmap = ioremap(selectmap_res->start, len); ++ if (!dev->selectmap) { ++ FAILMSG("Can't remap selectmap register"); ++ res = -ENXIO; ++ goto error; ++ } ++ dev->state = FPGADL_PAR_DEV_STATE_HAVE_IOREMAP; ++ ++ dev->fpgadl_dev.write_byte = selectmap_write_byte; ++ sprintf(dev->devname, "fpgadl_par%d", fpgadl_par_dev_count); ++ DBGMSG(" NAME = %s", dev->devname); ++ dev->fpgadl_dev.name = dev->devname; ++ dev->fpgadl_dev.devdata = dev; /* For our write_byte() callback */ ++ res = fpgadl_register_device(&dev->fpgadl_dev); ++ if (res < 0) { ++ FAILMSG("Error registering fpgadl_par device"); ++ goto error; ++ } ++ dev->state = FPGADL_PAR_DEV_STATE_FPGADL_DEV_REGISTERED; ++ ++ fpgadl_par_dev_count++; ++ ++ return 0; ++ ++error: ++ fpgadl_par_cleanup(dev); ++ return res; ++} ++ ++static int __devexit fpgadl_par_remove(struct platform_device *pdev) ++{ ++ struct fpgadl_par_dev_t *dev = platform_get_drvdata(pdev); ++ ++ DBGMSG("fpgadl_par_remove()"); ++ ++ fpgadl_par_cleanup(dev); ++ ++ return 0; ++} ++ ++static struct fpgadl_driver fpgadl_par_driver = { ++ .version = MODULE_VERSION_STR, ++ .module = THIS_MODULE, ++ .driver = { ++ .name = "fpgadl_par", ++ }, ++}; ++ ++static struct platform_driver fpgadl_platform_driver = { ++ .driver = { ++ .name = MODULE_NAME, ++ .owner = THIS_MODULE, ++ }, ++ .remove = fpgadl_par_remove, ++}; ++ ++static int __init fpgadl_par_init(void) ++{ ++ int res; ++ ++ DBGMSG("fpgadl_par_init()"); ++ ++ /* Register with the driver core. */ ++ res = fpgadl_register_driver(&fpgadl_par_driver); ++ if (res) { ++ FAILMSG("Can't register fpgadl parallel driver"); ++ return res; ++ } ++ ++ /* The probe function will be called for each platform device declared ++ * in board setup code. */ ++ res = platform_driver_probe(&fpgadl_platform_driver, ++ fpgadl_par_probe); ++ if (res) { ++ FAILMSG("platform_driver_probe() failed"); ++ return res; ++ } ++ ++ return 0; ++} ++module_init(fpgadl_par_init); ++ ++static void __exit fpgadl_par_exit(void) ++{ ++ DBGMSG("fpgadl_par_exit()"); ++ platform_driver_unregister(&fpgadl_platform_driver); ++ fpgadl_unregister_driver(&fpgadl_par_driver); ++} ++module_exit(fpgadl_par_exit); ++ ++MODULE_AUTHOR("Hugo Villeneuve "); ++MODULE_DESCRIPTION("FPGA parallel programming driver"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/fpgadl_ser.c b/drivers/misc/fpgadl_ser.c +new file mode 100644 +index 0000000..01ca5e0 +--- /dev/null ++++ b/drivers/misc/fpgadl_ser.c +@@ -0,0 +1,244 @@ ++/* ++ * fpgadl_ser.c - FPGA serial programming driver ++ * ++ * Copyright (C) 2008 Lyrtech ++ * ++ * Based on SH SCI SPI interface ++ * Copyright (c) 2008 Magnus Damm ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MODULE_NAME "fpgadl_ser" ++#define MODULE_VERSION_STR "v1.0" ++ ++/* Define this to enable verbose debug messages */ ++#define FPGADL_SER_DEBUG 1 ++ ++/* Module parameters */ ++static unsigned int fpgadl_ser_debug; ++EXPORT_SYMBOL_GPL(fpgadl_ser_debug); ++module_param_named(debug, fpgadl_ser_debug, int, 0644); ++ ++#ifdef FPGADL_SER_DEBUG ++#define INFOMSG(fmt, args...) \ ++do { \ ++ printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++#define DBGMSG(fmt, args...) \ ++do { if (fpgadl_ser_debug > 0) \ ++ printk(KERN_DEBUG "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++#define DBGMSG_ENTER() \ ++ DBGMSG("%s() enter", __func__); ++#define DBGMSG_LEAVE() \ ++ DBGMSG("%s() leave", __func__); ++#else ++#define INFOMSG(fmt, args...) do {} while (0) ++#define DBGMSG(fmt, args...) do {} while (0) ++#define DBGMSG_ENTER() do {} while (0) ++#define DBGMSG_LEAVE() do {} while (0) ++#endif ++ ++#define FAILMSG(fmt, args...) \ ++do { \ ++ printk(KERN_ERR "%s: "fmt"\n", MODULE_NAME, ## args); } while (0) ++ ++struct fpgadl_ser_dev_t { ++ char devname[32]; ++ enum { ++ FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED, ++ FPGADL_SER_DEV_STATE_SPI_SETUP, ++ FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED, ++ } state; ++ struct spi_transfer t; ++ struct spi_message m; ++ struct spi_device *spi; ++ struct fpgadl_device fpgadl_dev; ++}; ++ ++#define MAX_FPGADL_SER_DEV 5 ++ ++static int fpgadl_ser_dev_count; ++ ++static int fpgadl_ser_write_byte(struct fpgadl_device *fpgadl_dev, ++ u8 *data, int size) ++{ ++ int status; ++ struct fpgadl_ser_dev_t *fpgadl_ser_dev; ++ ++ fpgadl_ser_dev = (struct fpgadl_ser_dev_t *) fpgadl_dev->devdata; ++ ++ if (!data) { ++ FAILMSG("NULL data pointer"); ++ return -EFAULT; ++ } ++ ++ spi_message_init(&fpgadl_ser_dev->m); ++ fpgadl_ser_dev->t.tx_buf = data; ++ fpgadl_ser_dev->t.len = size; ++ spi_message_add_tail(&fpgadl_ser_dev->t, &fpgadl_ser_dev->m); ++ ++ status = spi_sync(fpgadl_ser_dev->spi, &fpgadl_ser_dev->m); ++ if (status < 0) ++ FAILMSG("spi_sync() failed (%d)", status); ++ ++ return status; ++} ++ ++static void fpgadl_ser_cleanup(struct fpgadl_ser_dev_t *dev) ++{ ++ DBGMSG_ENTER(); ++ ++ if (!dev) ++ return; ++ ++ switch (dev->state) { ++ case FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED: ++ fpgadl_unregister_device(&dev->fpgadl_dev); ++ case FPGADL_SER_DEV_STATE_SPI_SETUP: ++ case FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED: ++ kfree(dev); ++ break; ++ } ++} ++ ++static int __devinit fpgadl_ser_probe(struct spi_device *spi) ++{ ++ int res; ++ struct fpgadl_ser_dev_t *dev = NULL; ++ ++ DBGMSG_ENTER(); ++ ++ if (fpgadl_ser_dev_count == MAX_FPGADL_SER_DEV) { ++ FAILMSG("Maximum number of devices reached (%d)", ++ fpgadl_ser_dev_count); ++ res = -ENODEV; ++ goto error; ++ } ++ ++ DBGMSG(" device %d", fpgadl_ser_dev_count); ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) { ++ FAILMSG("Failed to allocate device structure"); ++ res = -ENOMEM; ++ goto error; ++ } ++ /* Set some default values. */ ++ dev->state = FPGADL_SER_DEV_STATE_STRUCT_ALLOCATED; ++ ++ DBGMSG(" SPI mode = %d", spi->mode); ++ ++ if (!spi->dev.platform_data) { ++ FAILMSG("Error getting platform data"); ++ res = -ENODEV; ++ goto error; ++ } ++ dev->fpgadl_dev.pdata = spi->dev.platform_data; ++ spi->dev.driver_data = dev; /* Private driver data */ ++ ++ spi->bits_per_word = 8; /* Size of Tx and Rx transfers. */ ++ res = spi_setup(spi); ++ if (res < 0) { ++ FAILMSG("Error setting-up SPI"); ++ goto error; ++ } ++ dev->spi = spi; ++ dev->state = FPGADL_SER_DEV_STATE_SPI_SETUP; ++ ++ dev->fpgadl_dev.write_byte = fpgadl_ser_write_byte; ++ sprintf(dev->devname, "fpgadl_ser%d", fpgadl_ser_dev_count); ++ DBGMSG(" NAME = %s", dev->devname); ++ dev->fpgadl_dev.name = dev->devname; ++ dev->fpgadl_dev.devdata = dev; /* For our write_byte() callback */ ++ res = fpgadl_register_device(&dev->fpgadl_dev); ++ if (res < 0) { ++ FAILMSG("Error registering fpgadl_ser device"); ++ goto error; ++ } ++ dev->state = FPGADL_SER_DEV_STATE_FPGADL_DEV_REGISTERED; ++ ++ fpgadl_ser_dev_count++; ++ ++ return 0; ++ ++error: ++ fpgadl_ser_cleanup(dev); ++ return res; ++} ++ ++static int __devexit fpgadl_ser_remove(struct spi_device *spi) ++{ ++ struct fpgadl_ser_dev_t *dev = spi_get_drvdata(spi); ++ ++ DBGMSG_ENTER(); ++ fpgadl_ser_cleanup(dev); ++ return 0; ++} ++ ++static struct spi_driver fpgadl_ser_spi_driver = { ++ .driver = { ++ .name = MODULE_NAME, ++ .bus = &spi_bus_type, ++ .owner = THIS_MODULE, ++ }, ++ .probe = fpgadl_ser_probe, ++ .remove = fpgadl_ser_remove, ++}; ++ ++static struct fpgadl_driver fpgadl_ser_driver = { ++ .version = MODULE_VERSION_STR, ++ .module = THIS_MODULE, ++ .driver = { ++ .name = "fpgadl_ser", ++ }, ++}; ++ ++static int __init fpgadl_ser_init(void) ++{ ++ int res; ++ ++ DBGMSG_ENTER(); ++ ++ /* Register with the driver core. */ ++ res = fpgadl_register_driver(&fpgadl_ser_driver); ++ if (res) { ++ FAILMSG("Can't register fpgadl serial driver"); ++ return res; ++ } ++ ++ return spi_register_driver(&fpgadl_ser_spi_driver); ++} ++module_init(fpgadl_ser_init); ++ ++static void __exit fpgadl_ser_exit(void) ++{ ++ DBGMSG_ENTER(); ++ spi_unregister_driver(&fpgadl_ser_spi_driver); ++ fpgadl_unregister_driver(&fpgadl_ser_driver); ++} ++module_exit(fpgadl_ser_exit); ++ ++MODULE_DESCRIPTION("FPGA serial programming driver"); ++MODULE_AUTHOR("Hugo Villeneuve"); ++MODULE_LICENSE("GPL"); +diff --git a/include/linux/fpgadl.h b/include/linux/fpgadl.h +new file mode 100644 +index 0000000..27d83f1 +--- /dev/null ++++ b/include/linux/fpgadl.h +@@ -0,0 +1,96 @@ ++/* ++ * FPGA bitstream load header file. ++ * ++ * Copyright (C) 2008 Lyrtech ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#ifndef FPGADL_H ++#define FPGADL_H 1 ++ ++#include ++ ++/* FPGA device-specific informations and functions. */ ++struct fpgadl_pdata_t { ++ enum { ++ FPGA_VENDOR_XILINX, ++ FPGA_VENDOR_ALTERA, ++ } fpga_vendor; ++ enum { ++ FPGA_FAMILY_XILINX_XC3S, ++ FPGA_FAMILY_XILINX_XC4V, ++ } fpga_family; ++ ssize_t payload_full_size; ++ u8 program_b; ++ u8 init_b; ++ u8 done; ++ ch