Tuesday, January 13, 2009

Gnu Makefile by example



vendor/config/bfin/config.arch:

.EXPORT_ALL_VARIABLES:

# tells make to export all variables to child processes by default. make adds the variable and
# its value to the environment for running each command. The sub-make, in turn, uses the
# environment to initialize its table of variable values.


include $(ROOTDIR)/vendors/config/common/config.arch

############################################################################
#
# The makefiles need to know how to do things in different contexts
# To save some pain we put it all here
#
# First settings we always want for all builds
#

MACHINE = bfin # this is for uClibc
ARCH = blackfin # this is for the kernel
ENDIAN = little

ifeq ($(CONFIG_FMT_USE_FDPIC_ELF),y)
CONFIGURE_HOST := bfin-linux-uclibc
CONFIGURE_SHARED_ENABLE := --enable-shared
CONFIGURE_SHARED_WITH := --with-shared
else
CONFIGURE_HOST := bfin-uclinux
CONFIGURE_SHARED_ENABLE := --disable-shared
CONFIGURE_SHARED_WITH := --without-shared
endif
CROSS_COMPILE := $(CONFIGURE_HOST)-
CROSS := $(CROSS_COMPILE)
KERNEL_CROSS_COMPILE := bfin-uclinux-

# ":=" - Simple Expanded Variable. The value of a simply expanded variable is scanned once and for all, expanding any references to other variables and functions, when the variable is defined. This makes Makefile programing simple.

CC = $(CROSS_COMPILE)gcc
AS = $(CROSS_COMPILE)as
CXX = $(CROSS_COMPILE)g++
AR = $(CROSS_COMPILE)ar
LD = $(CROSS_COMPILE)ld
NM = $(CROSS_COMPILE)nm
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
RANLIB = $(CROSS_COMPILE)ranlib
ELF2FLT = $(CROSS_COMPILE)elf2flt
STRIPTOOL = $(CROSS_COMPILE)strip
STRIP = $(STRIPTOOL)
CC_FOR_BUILD = gcc
CONFIG_SITE = $(ROOTDIR)/vendors/config/config.site

QMAKE = $(CROSS_COMPILE)qmake

MKIMAGE = $(ROOTDIR)/$(LINUXDIR)/scripts/mkuboot.sh
MKFS_CRAMFS = $(ROOTDIR)/user/cramfs/host_build/mkcramfs
MKFS_EXT2 = $(ROOTDIR)/user/genext2fs/build-host/genext2fs
MKFS_JFFS2 = $(ROOTDIR)/user/mtd-utils/mkfs.jffs2
MTD_SUMTOOL = $(ROOTDIR)/user/mtd-utils/sumtool
MKFS_ROMFS = $(ROOTDIR)/user/genromfs/genromfs
MKFS_UBIFS = $(ROOTDIR)/user/mtd-utils/mkfs.ubifs
MKFS_YAFFS = $(ROOTDIR)/user/yaffs-utils/mkfs.yaffs
MKFS_YAFFS2 = $(ROOTDIR)/user/yaffs-utils/mkfs.yaffs2

############################################################################
#
# Settings for configure / autotools
#

CONFIGURE_BUILD := $(shell sh $(ROOTDIR)/tools/config.guess)

# Here "shell" is a function - The shell function performs the same function that backquotes (``') perform in most shells: it does command expansion.

CONFIGURE_OPTS := \
--host=$(CONFIGURE_HOST) \
--build=$(CONFIGURE_BUILD) \
--prefix=/usr \
--sysconfdir=/etc \
--datadir=/usr/share \
--mandir=/usr/share/man \
--infodir=/usr/share/info \
--localstatedir=/var/lib \
--disable-dependency-tracking \
--enable-fast-install
ifneq ($(findstring s,$(MAKEFLAGS)),)
CONFIGURE_OPTS += --quiet
endif

# $(findstring find,text) - Locate find in text.
# MAKEFLAGS - The flags given to make. You can set this in the environment or a makefile to set flags.
# "-s" : silent, quiet

cpu-$(CONFIG_BF512) := bf512
cpu-$(CONFIG_BF514) := bf514
cpu-$(CONFIG_BF516) := bf516
cpu-$(CONFIG_BF518) := bf518
cpu-$(CONFIG_BF522) := bf522
cpu-$(CONFIG_BF523) := bf523
cpu-$(CONFIG_BF524) := bf524
cpu-$(CONFIG_BF525) := bf525
cpu-$(CONFIG_BF526) := bf526
cpu-$(CONFIG_BF527) := bf527
cpu-$(CONFIG_BF531) := bf531
cpu-$(CONFIG_BF532) := bf532
cpu-$(CONFIG_BF533) := bf533
cpu-$(CONFIG_BF534) := bf534
cpu-$(CONFIG_BF536) := bf536
cpu-$(CONFIG_BF537) := bf537
cpu-$(CONFIG_BF538) := bf538
cpu-$(CONFIG_BF539) := bf539
cpu-$(CONFIG_BF542) := bf542
cpu-$(CONFIG_BF544) := bf544
cpu-$(CONFIG_BF547) := bf547
cpu-$(CONFIG_BF548) := bf548
cpu-$(CONFIG_BF549) := bf549
cpu-$(CONFIG_BF561) := bf561

rev-$(CONFIG_BF_REV_0_0) := 0.0
rev-$(CONFIG_BF_REV_0_1) := 0.1
rev-$(CONFIG_BF_REV_0_2) := 0.2
rev-$(CONFIG_BF_REV_0_3) := 0.3
rev-$(CONFIG_BF_REV_0_4) := 0.4
rev-$(CONFIG_BF_REV_0_5) := 0.5
rev-$(CONFIG_BF_REV_0_6) := 0.6
rev-$(CONFIG_BF_REV_ANY) := any
rev-$(CONFIG_BF_REV_NONE) := none
ifeq ($(rev-y),)
$(warning )
$(warning The Blackfin Silicon Revision you are targetting is not known.)
$(warning Please file a bug report about this.)
$(warning )
rev-y := any
endif

ifeq ($(cpu-y),)
$(warning )
$(warning The Blackfin CPU you are targetting is not known.)
$(warning Please file a bug report about this.)
$(warning )
else
CPUFLAGS = -mcpu=$(cpu-y)-$(rev-y)
endif

############################################################################
#
# Set up all our fun CFLAGS/CPPFLAGS/LDFLAGS. Normalize our
# settings so we don't differentiate between user and lib.
#

ifneq ($(UCLINUX_BUILD_USER)$(UCLINUX_BUILD_LIB),)

CFLAGS-y := -pipe -Wall
CXXFLAGS-y := -pipe -Wall
CPPFLAGS-y := -DEMBED -D__uClinux__ -I$(ROOTDIR)
LDFLAGS-y :=
FLTFLAGS-y :=

CONFIG_ALL_DEBUG := n
ifdef CONFIG_LIB_DEBUG
CONFIG_ALL_DEBUG := y
endif
ifdef CONFIG_USER_DEBUG
CONFIG_ALL_DEBUG := y
endif

ifeq ($(CONFIG_ALL_DEBUG),y)
CFLAGS-y += -O0 -g
STRIPTOOL := echo
STRIP := $(STRIPTOOL)
else
CFLAGS-y += $(subst ",,$(strip $(CONFIG_USER_CFLAGS)))
endif

# $(strip string) - Remove excess whitespace characters from string.
# $(subst from,to,text) - Replace from with to in text.

CFLAGS-$(CONFIG_BLACKFIN_CHECK_STACKFLOW) += -mstack-check-l1
CFLAGS-$(CONFIG_BLACKFIN_CHECK_POINTER) += -fmudflap -lmudflap

LDFLAGS-$(CONFIG_FMT_USE_FLAT) += -Wl,-elf2flt
LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-elf2flt
LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -Wl,-elf2flt

CFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data
LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data

CFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -mid-shared-library
CFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -msep-data
LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-shared-lib-id,0 -mid-shared-library
LDFLAGS-$(CONFIG_FMT_USE_SEP_DATA) += -Wl,-shared-lib-id,0 -msep-data

#
# This will prevent building up of code in lib/ as shared libs.
# You will need to build/link those by hand anyways ...
#
CFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -mshared-library-id=0
FLAT_LIBC := $(shell $(CC) $(CPUFLAGS) -mid-shared-library -print-file-name=libc.gdb)
LDFLAGS-$(CONFIG_FMT_USE_SHARED_FLAT) += -Wl,-R,$(FLAT_LIBC)

CFLAGS := $(CFLAGS-y) $(VENDOR_CFLAGS) $(CPUFLAGS)
CXXFLAGS := $(CXXFLAGS-y) $(VENDOR_CXXFLAGS) $(CPUFLAGS)
CPPFLAGS := $(CPPFLAGS-y) $(VENDOR_CPPFLAGS) $(CPUFLAGS)
LDFLAGS := $(LDFLAGS-y) $(VENDOR_LDFLAGS) $(CPUFLAGS)
FLTFLAGS := $(FLTFLAGS-y) $(VENDOR_FLTFLAGS)

endif

Monday, July 28, 2008

blackfin spi device driver



/********************** ADAM **************************************/

The SPI master is registered as a platform devices, while SPI slave devices are registered
as devices in the SPI bus.

SPI Bus
~~~~~~~
spi.c: spi_init()
status = bus_register(&spi_bus_type);
status = class_register(&spi_master_class);

root:/sys/bus/spi> ls -lR
.:
drwxr-xr-x 2 root root 0 Jan 1 01:47 devices
drwxr-xr-x 3 root root 0 Jan 1 2007 drivers
-rw-r--r-- 1 root root 4096 Jan 1 01:47 drivers_autoprobe
--w------- 1 root root 4096 Jan 1 01:47 drivers_probe

./devices:
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../devices/platform/bfin-spi.0/spi0.1

./drivers:
drwxr-xr-x 2 root root 0 Jan 1 01:47 spidev

./drivers/spidev:
--w------- 1 root root 4096 Jan 1 01:47 bind
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1
--w------- 1 root root 4096 Jan 1 01:47 unbind



Setup the master (SPI controller)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The SPI master device is registered as a platform device:
// stamp.c:

struct platform_device {
const char *name;
u32 id;
struct device dev;
u32 num_resources;
struct resource *resource;
};

//---------------------------------------------------------------
stamp.c:

static struct resource bfin_spi0_resource[] = {
[0] = {
.start = SPI0_REGBASE,
.end = SPI0_REGBASE + 0xFF,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = CH_SPI,
.end = CH_SPI,
.flags = IORESOURCE_IRQ,
}
};

/* SPI controller data */
static struct bfin5xx_spi_master bfin_spi0_info = {
.num_chipselect = 8,
.enable_dma = 1, /* master has the ability to do dma transfer */
.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
};

static struct platform_device bfin_spi0_device = {
.name = "bfin-spi",
.id = 0, /* Bus number */
.num_resources = ARRAY_SIZE(bfin_spi0_resource),
.resource = bfin_spi0_resource,
.dev = {
.platform_data = &bfin_spi0_info, /* Passed to driver */
},
};

static int __init stamp_init(void) {
platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));

}
//-------------------------------------------------------------------------

The driver for SPI master:

static struct platform_driver bfin5xx_spi_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin5xx_spi_suspend,
.resume = bfin5xx_spi_resume,
.remove = __devexit_p(bfin5xx_spi_remove),
}

/**
* platform_driver_probe - register driver for non-hotpluggable device
* @drv: platform driver structure
* @probe: the driver probe routine, probably from an __init section
*
* Use this instead of platform_driver_register() when you know the device
* is not hotpluggable and has already been registered, and you want to
* remove its run-once probe() infrastructure from memory after the driver
* has bound to the device.
*
* One typical use for this would be with drivers for controllers integrated
* into system-on-chip processors, where the controller devices have been
* configured as part of board setup.
*
* Returns zero if the driver registered and bound to a device, else returns
* a negative error code and with the driver not registered.
*/
static int __init bfin5xx_spi_init(void)
{
return platform_driver_probe(&bfin5xx_spi_driver, bfin5xx_spi_probe);
}

------------------------------------------------------------------------------------------
Bind spi slave devices and spi driver.

platform_probe()
--> bfin_spi_probe() // spi_bf5xx.c
--> spi_register_master() // spi.c
--> scan_board_info() // for all the devices in the table defined in board.c (stamp.c)
--> spi_new_device()
--> master->setup() // set up the new device HW
--> device_register()

-----------------------------------------------------------------
This driver defines bellow routine for spi master device
master->cleanup = cleanup;
master->setup = setup;
master->transfer = transfer;
------------------------------------------------------------------
Set up queues for transfer:
// spi_bf5xx.c
bfin_spi_probe()
---> init_queue()
---> tasklet_init(&drv_data->pump_transfers,
pump_transfers, (unsigned long)drv_data);
---> INIT_WORK(&drv_data->pump_messages, pump_messages);

root:/sys/devices/platform/bfin-spi.0> ls -lR
.:
lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform
lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi
-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias
drwxr-xr-x 2 root root 0 Jan 1 2007 power
drwxr-xr-x 3 root root 0 Jan 1 2007 spi0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent

./power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup

./spi0.1:
lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi
lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev
-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias
drwxr-xr-x 2 root root 0 Jan 1 2007 power
lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi
-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent

./spi0.1/power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup



For a SPI slave driver:
~~~~~~~~~~~~~~~~~

* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link. It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages). These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.

struct spi_driver {
int (*probe)(struct spi_device *spi);
int (*remove)(struct spi_device *spi);
void (*shutdown)(struct spi_device *spi);
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
int (*resume)(struct spi_device *spi);
struct device_driver driver;
};

static struct spi_driver bfin_spi_adc_driver = {
.driver = {
.name = "bfin_spi_adc",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = bfin_spi_adc_probe,
.remove = __devexit_p(bfin_spi_adc_remove),
};


spi_register_driver(&bfin_spi_adc_driver);


struct bfin_spi_adc {
int opened;
unsigned short *buffer;
int hz;
int cont;
struct spi_device *spidev;
dma_addr_t dma_handle;
};

struct bfin_spi_adc spi_adc;


struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
#define SPI_3WIRE 0x10 /* SI/SO signals shared */
#define SPI_LOOP 0x20 /* loopback mode */
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
const char *modalias;
};


root:/sys/bus/spi/drivers/spidev> ls -lR
.:
--w------- 1 root root 4096 Jan 1 01:47 bind
lrwxrwxrwx 1 root root 0 Jan 1 01:47 spi0.1 -> ../../../../devices/platform/bfin-spi.0/spi0.1
--w------- 1 root root 4096 Jan 1 01:47 unbind

root:/sys/devices/platform/bfin-spi.0> ls -lR
.:
lrwxrwxrwx 1 root root 0 Jan 1 01:48 bus -> ../../../bus/platform
lrwxrwxrwx 1 root root 0 Jan 1 01:48 driver -> ../../../bus/platform/drivers/bfin-spi
-r--r--r-- 1 root root 4096 Jan 1 01:48 modalias
drwxr-xr-x 2 root root 0 Jan 1 01:49 power
drwxr-xr-x 3 root root 0 Jan 1 01:49 spi0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:48 spi_master:spi0 -> ../../../class/spi_master/spi0
lrwxrwxrwx 1 root root 0 Jan 1 01:48 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 Jan 1 01:48 uevent

./power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup

./spi0.1:
lrwxrwxrwx 1 root root 0 Jan 1 01:49 bus -> ../../../../bus/spi
lrwxrwxrwx 1 root root 0 Jan 1 01:49 driver -> ../../../../bus/spi/drivers/spidev
-r--r--r-- 1 root root 4096 Jan 1 01:49 modalias
drwxr-xr-x 2 root root 0 Jan 1 01:49 power
lrwxrwxrwx 1 root root 0 Jan 1 01:49 spidev:spidev0.1 -> ../../../../class/spidev/spidev0.1
lrwxrwxrwx 1 root root 0 Jan 1 01:49 subsystem -> ../../../../bus/spi
-rw-r--r-- 1 root root 4096 Jan 1 01:49 uevent

./spi0.1/power:
-rw-r--r-- 1 root root 4096 Jan 1 01:49 wakeup

-------------------------------------------------
Bind the SPI protocol driver to SPI device:

1. In driver init: calls spi_register_driver() --> driver_register()

2. when device_register() is called, the "Driver Core" will search the list of drivers,
and check whether the device "match" with a driver.

3. when driver_register() get called, the "Driver Core" will also scan existing devices



To send a message:
~~~~~~~~~~~~~~~~~

spi_sync() // spi.c
--> spi_async();
--> master->transfer(); // spi_bf5xx.c
--> queue_work(drv_data->workqueue, &drv_data->pump_messages);
--> pump_messages()
--> tasklet_schedule(&drv_data->pump_transfers) //activate the tasklet
--> pump_taskfer()
--> wait_for_completion(&done)


miscellaneous device
~~~~~~~~~~~~~~~~~~~~~
Misc (or miscellaneous) drivers are simple char drivers that share certain common characteristics. The kernel
abstracts these commonalities into an API (implemented in drivers/char/misc.c), and this simplifies the way
these drivers are initialized. All misc devices are assigned a major number of 10, but each can choose a single
minor number. So, if a char driver needs to drive multiple devices as in the CMOS example discussed earlier, it's
probably not a candidate for being a misc driver.



Platform devices
~~~~~~~~~~~~~~~~
Platform devices are devices that typically appear as autonomous
entities in the system. This includes legacy port-based devices and
host bridges to peripheral buses, and most controllers integrated
into system-on-chip platforms. What they usually have in common
is direct addressing from a CPU bus. Rarely, a platform_device will
be connected through a segment of some other kind of bus; but its
registers will still be directly addressable.

Platform devices are given a name, used in driver binding, and a
list of resources such as addresses and IRQs.


Blog Archive